home *** CD-ROM | disk | FTP | other *** search
/ Symantec Visual Cafe for Java 2.5 / symantec-visual-cafe-2.5-database-dev-edition.iso / Visual Cafe Pro v1.0 / SOURCE.BIN / Grid.java < prev    next >
Encoding:
Java Source  |  1997-06-19  |  124.0 KB  |  4,394 lines

  1. /*
  2.  * Grid.java   1.0   12 Jan 1997
  3.  *
  4.  * Copyright (c) 1996 Krumel & Associates, Inc.  All Rights Reserved.
  5.  *
  6.  * This software is provided as is.  Krumel & Associates shall not be liable
  7.  * for any damages suffered by licensee as a result of using, modifying or
  8.  * distributing this software or its derivatives.
  9.  */
  10.  
  11. package symantec.itools.db.awt;
  12.  
  13. import java.awt.*;
  14. import java.util.*;
  15. import java.io.*;
  16.  
  17. /**
  18.  * A spreadsheet style control.<p>
  19.  *
  20.  * All column and row numbers are one relative.<p>
  21.  *
  22.  * The Grid supports column and row headings.  The row headings may be blank or
  23.  * autonumbered based on a user defined base number.<p>
  24.  *
  25.  * The Grid provides support for a toolbar along the bottom row to the right
  26.  * of the horizontal scrollbar.  Any type of component may be added to the toolbar
  27.  * or pre-defined buttons may be added using the available addXXXXButton methods.<p>
  28.  *
  29.  * To increase the modularity of the grid, events and exceptions are passed to
  30.  * an EventHandler object when set.  Event IDs have been defined for the table
  31.  * and cells.  Additional events are generated by the toolbar components and
  32.  * forwarded to the EventHandler as well.  Of course the tradional event model
  33.  * of JDK 1.0.2 is also supported but tends to make GUI code functional.
  34.  * All lighting, inserts, gotos, ... are performed by the EventHandler. <p>
  35.  *
  36.  * To further increase modularity, data is kept in DataSources.  A default
  37.  * DataSource if one is not defined that simply stores the data in a Matrix
  38.  * instance.  If a RelationView is specified in the constructor, then a special
  39.  * DataSource is created to drive the Grid off of the database query.<p>
  40.  *
  41.  * A number of APIs are defined to allow the grid color, font, and other visual
  42.  * styles to be effected.
  43.  *
  44.  * @version 1.0   12 Jan 1997
  45.  * @author  Andy Krumel - Krumel & Associates, Inc
  46.  */
  47. public class Grid extends Panel /* implements Runnable */ {
  48.     boolean         autoRedraw = true;
  49.     boolean         onSolaris;
  50.     Button          button;
  51.     Panel           toolbar;
  52.     Panel           bottomPanel;
  53.     Vector          toolbarComponents = new Vector();
  54.     TvEventHandler  eventHandler;
  55.     Matrix          cells;
  56.     Matrix          colHeadings;
  57.     Matrix          cellAttributes;      //cell hints
  58.     Matrix          headingAttributes;   //col heading hints
  59.  
  60.  
  61.     int             preferredRowCount = 10;
  62.     int             splitters[];
  63.     boolean         fillLastColumn;
  64.     Scrollbar       vsb;
  65.     Scrollbar       hsb;
  66.     int             cursor = Frame.DEFAULT_CURSOR;
  67.     long            clickTime;
  68.     int             topRow;
  69.     int             leftCol = 1;
  70.     int             dragColumn = -1;
  71.     int             xDragLast = -1;
  72.     boolean         isDragging;
  73.     int             headingHeight;
  74.     int             cellHeight;
  75.     int             clickMargin = 5;
  76.     int             currentCursor = Frame.DEFAULT_CURSOR;
  77.     Image           im;
  78.     Graphics        gg;
  79.     int             height;
  80.     int             width;
  81.     int             vsbPosition;
  82.     int             hsbPosition;
  83.     long            scrollbarTimer;
  84.     boolean         fetchMode = false;
  85.  
  86.     DataSource              dataSource;
  87.     DataSource              headingSource;
  88.     DefaultDataSource       rowHeadingSource;
  89.  
  90.     CellHints       hints;
  91.     TableCell       currSelectedCell = null;
  92.     TableCell       currCaptureCell = null;
  93.       TableCell       defaultCell;
  94.  
  95.     boolean         tabbed;
  96.     symantec.itools.db.pro.RelationViewMetaData rvmd;
  97. //-----------------------------------------------------------------------------
  98. //                          Column Heading Variables
  99. //-----------------------------------------------------------------------------
  100.     int             rowHeadingWidth = 30;
  101.     CellHints       rowHeadingHints;
  102.     boolean         autoCreate = true;
  103.     int             rowHeadingLabelStyle = BLANK;
  104.     int             firstNumber = 1;    //used for autonumbering
  105.     TableCell       headingCell;        //the default row heading cell
  106.     TableCell       currHeadingCell;    //the one currently being pressed
  107.                                         //this is null if not in use
  108.     TableCell       cornerCell;         //the default row heading cell
  109.  
  110.     //row heading styles
  111.  
  112.     /**
  113.      * Autonumber row heading style
  114.      */
  115.     public final static int AUTONUMBER = 0;
  116.     /**
  117.      * Blank row headings - the default
  118.      */
  119.     public final static int BLANK = 1;
  120.  
  121.     /**
  122.      * User defined style - not currently supported
  123.      */
  124.     public final static int USER_DEFINED = 2;
  125.  
  126.     /**
  127.      * TableCell type as returned by TableCell.type()
  128.      */
  129.     public final static Integer TABLE_CELL = new Integer(1);
  130.     /**
  131.      * The corner cell type as returned by TableCell.type()
  132.      */
  133.     public final static Integer CORNER_CELL = new Integer(2);
  134.     /**
  135.      * Column heading type as returned by TableCell.type()
  136.      */
  137.     public final static Integer COLUMN_HEADING = new Integer(3);
  138.     /**
  139.      * Row heading cell type as returned by TableCell.type()
  140.      */
  141.     public final static Integer ROW_HEADING = new Integer(4);
  142.  
  143.  
  144.     /**
  145.      * default append row toolbar button label
  146.      */
  147.     public static String appendRowLabel = "Append";
  148.     /**
  149.      * default delete row toolbar button label
  150.      */
  151.     public static String deleteRowLabel = "Delete";
  152.     /**
  153.      * default insert row toolbar button label
  154.      */
  155.     public static String insertRowLabel = "Insert";
  156.     /**
  157.      * default goto row toolbar button label
  158.      */
  159.     public static String gotoRowLabel = "Goto >>>";
  160.     /**
  161.      * default save row toolbar button label
  162.      */
  163.     public static String saveLabel = "Save";
  164.     /**
  165.      * default restart row toolbar button label
  166.      */
  167.     public static String restartLabel = "Restart";
  168.     /**
  169.      * default undo row toolbar button label
  170.      */
  171.     public static String undoRowLabel = "Undo";
  172.     /**
  173.      * default undelete row toolbar button label
  174.      */
  175.     public static String undeleteRowLabel = "Undelete";
  176.  
  177.  
  178. //-----------------------------------------------------------------------------
  179. //                          Event IDs
  180. //-----------------------------------------------------------------------------
  181.     /**
  182.      * Grid level event for when grid got focus
  183.      */
  184.     public final static int GOT_FOCUS = Event.GOT_FOCUS;
  185.     /**
  186.      * Grid level event for when grid lost focus
  187.      */
  188.     public final static int LOST_FOCUS = Event.LOST_FOCUS;
  189.     /**
  190.      * Grid level event for when row inserted
  191.      */
  192.     public final static int INSERT = 3;     //insert row above specified row
  193.     /**
  194.      * Grid level event for when rpw is deleted
  195.      */
  196.     public final static int DELETE = 4;     //delete specified row
  197.     /**
  198.      * Grid level event for when row is appended
  199.      */
  200.     public final static int APPEND = 5;     //add row to end of data
  201.     /**
  202.      * Grid level event for when row is undeleted
  203.      */
  204.     public final static int UNDELETE = 7;
  205.  
  206.     /**
  207.      * Base cell level event ID
  208.      */
  209.     public final static int CELL_EVENT = 50;
  210.     /**
  211.      * Cell level event for when cell is button an pushed down
  212.      */
  213.     public final static int BUTTON_DOWN_EVENT = CELL_EVENT;
  214.     /**
  215.      * Cell level event for when cell is button a mouse is released over button
  216.      */
  217.     public final static int BUTTON_UP_EVENT = CELL_EVENT + 1;
  218.     /**
  219.      * Button depressed but mouse moved off button then back on
  220.      */
  221.     public final static int BUTTON_FLICKER_DOWN_EVENT = CELL_EVENT + 2;
  222.     /**
  223.      * Button depressed but mouse moved off button
  224.      */
  225.     public final static int BUTTON_FLICKER_UP_EVENT = CELL_EVENT + 3;
  226.     /**
  227.      * User requested the most recent changes to be undone and the latest
  228.      * committed data be reset
  229.      */
  230.     public final static int UNDO_CELL_EVENT = CELL_EVENT + 4;
  231.     /**
  232.      * Cell level event for when cell gets focus
  233.      */
  234.     public final static int GOT_CELL_FOCUS = CELL_EVENT + 5;
  235.     /**
  236.      * Cell level event for when cell loses focus
  237.      */
  238.     public final static int LOST_CELL_FOCUS = CELL_EVENT + 6;
  239.     /**
  240.      * User performed action to change contents of a cell (like a key press)
  241.      */
  242.     public final static int CELL_CONTENT_CHANGE = CELL_EVENT + 7;
  243.     /**
  244.      * Cell level event for when key is pressed in cell
  245.      */
  246.     public final static int CELL_KEY_DOWN = CELL_EVENT + 8;
  247.     /**
  248.      * Cell level event for when key is released in cell
  249.      */
  250.     public final static int CELL_KEY_UP = CELL_EVENT + 9;
  251.     /**
  252.      * Cell level event for when mouse is released in cell
  253.      */
  254.     public final static int CELL_MOUSE_UP = CELL_EVENT + 10;
  255.     /**
  256.      * Cell level event for when mouse is pushed down in cell
  257.      */
  258.     public final static int CELL_MOUSE_DOWN = CELL_EVENT + 11;
  259.     /**
  260.      * Cell level event for when mouse is dragged in cell
  261.      */
  262.     public final static int CELL_MOUSE_DRAG = CELL_EVENT + 12;
  263.     /**
  264.      * Double click within cell
  265.      */
  266.     public final static int CELL_MOUSE_DOUBLE = CELL_EVENT + 13;
  267.  
  268.  
  269. //-----------------------------------------------------------------------------
  270. //                          Constant IDs
  271. //-----------------------------------------------------------------------------
  272.     /**
  273.      * Time to register a double click (in milliseconds).
  274.      */
  275.     public final static long CLICKTHRESHOLD = 250;
  276.     /**
  277.      * Left-justify constant.
  278.      */
  279.     public final static int LEFT = 0;
  280.     /**
  281.      * Center-justify constant.
  282.      */
  283.     public final static int CENTER = 1;
  284.     /**
  285.      * Right-justify constant.
  286.      */
  287.     public final static int RIGHT = 2;
  288.  
  289.     //Cell line styles - not implemented yet
  290.     final static int NO_LINE = 0;
  291.     final static int THIN_LINE = 1;
  292.     final static int THICK_LINE = 2;
  293.     final static int DASHED_LINE = 3;
  294.  
  295.     //Cell vertical align styles
  296.     final static int TOP = 0;
  297. //    public final static int CENTER = 1;  //already defined
  298.     final static int BOTTOM = 2;
  299.  
  300.  
  301.     static TableCell defaultHeadingCell_ = new ButtonCell();
  302.     static boolean defaultsInitialized = false;
  303.  
  304.     //static initializers don't work in Explorer so we use a function
  305.     static void initDefaults() {
  306.         if (!defaultsInitialized) {
  307.             defaultHeadingCell_.setCoordinates(new Coordinate(0,0));
  308.             defaultHeadingCell_.type(TableCell.ROW_HEADING);
  309.             defaultsInitialized = true;
  310.         }
  311.     }
  312.  
  313.     /**
  314.      * Default constructor for new Grid.
  315.      */
  316.     public Grid()  {
  317.         this(0,0);
  318.     }
  319.  
  320.     /**
  321.      * Constructs a new Grid with the specified number of columns.
  322.      * @param cols the number of columns
  323.      */
  324.     public Grid(int cols) {
  325.         this(0,cols);
  326.     }
  327.  
  328.     /**
  329.      * Constructs a new Grid with the preferred height based on
  330.      * specified number of rows.
  331.      * @param rows the number of rows to show
  332.      */
  333.     public Grid(long rows)  {
  334.         this(rows, 0);
  335.     }
  336.  
  337.     /**
  338.      * Constructs a new Grid with the spcified number of columns
  339.      * and whether multiple row selection allowed.
  340.      * @param rows the number of rows to show
  341.      * @param cols the number of columns
  342.      */
  343.     public Grid(long rows, int cols) {
  344.         dataSource = new DefaultDataSource(this);
  345.         assignDefaults();
  346.         dataSource.setDefaultData();
  347.         createColumns(cols);
  348.         setupAutonumbering(1);
  349.         setBackground(Color.white);
  350.       
  351.     try
  352.         {
  353.         for( int i=0; i < rows; i++)
  354.             {
  355.             appendRow();
  356.             }
  357.  
  358.         for(int i=0; i< cols;i++)
  359.             {
  360.             setHeading( "Column:"+(i+1), i+1, 10);
  361.             }
  362.         } catch( Exception e)
  363.         {System.out.println( "EXCEPTION " + e);}
  364.         preferredRowCount = (int)rows;
  365.     }
  366.  
  367.     /**
  368.      * Constructs a new Grid with the spcified number of columns
  369.      * and whether multiple row selection allowed, and background color.
  370.      * @param cols the number of columns
  371.      * @bg Color instance for background color
  372.      */
  373.     public Grid(int cols, Color bg) {
  374.         dataSource = new DefaultDataSource(this);
  375.         assignDefaults();
  376.         dataSource.setDefaultData();
  377.         createColumns(cols);
  378.         setupAutonumbering(1);
  379.         setBackground(bg);
  380.     }
  381.  
  382.  
  383.     /**
  384.      * Constructs a new Grid using the specified RelationView.  Grid will
  385.      * automatically setup the columns.
  386.      * @param relView the RelationView on which to drive the Grid
  387.      * @exception symjava.sql.SQLException Thrown when the Grid cannot
  388.      *          be successfully setup due to a database problem
  389.      */
  390.     public Grid(symantec.itools.db.pro.RelationView relView)
  391.         throws symjava.sql.SQLException
  392.     {
  393.         this(relView, null,0);
  394.     }
  395.  
  396.     public Grid(symantec.itools.db.pro.RelationView relView,int coltoshow)
  397.         throws symjava.sql.SQLException
  398.     {
  399.  
  400.         this(relView, null, coltoshow);
  401.  
  402.  
  403.     }
  404.  
  405.     symantec.itools.db.pro.RelationView relation,
  406.                                         master;
  407.  
  408.     /**
  409.      * Constructs a new Grid that is attached to a detail RelationView.
  410.      * @param relView the detail view to attach the Grid
  411.      * @param masterView the master view
  412.      * @exception symjava.sql.SQLException Thrown when the Grid cannot
  413.      *          be successfully setup due to a database problem
  414.      */
  415.     public Grid(symantec.itools.db.pro.RelationView relView,
  416.                 symantec.itools.db.pro.RelationView masterView,
  417.                 int coltoshow)
  418.         throws symjava.sql.SQLException
  419.     {
  420.         name = relView.getName();
  421.         relation = relView;
  422.         master =masterView;
  423.  
  424.         DbaDataStore    store = new DbaDataStore(relView, masterView);
  425.         //if(coltos!=0)
  426.         store.setColtoShow(coltoshow);
  427.  
  428.         dataSource = new DbDataSource(this, store, store, store);
  429.  
  430.         dataSource.setDefaultData();
  431.  
  432.         assignDefaults();
  433.  
  434.         if (dataSource.supportsMeta()) {
  435.             try {
  436.                 dataSource.setupGrid(this);
  437.             } catch(Exception e) {
  438.                 e.printStackTrace();
  439.             }
  440.         }
  441.         rvmd = relView.getMetaData();
  442.  
  443.         setupAutonumbering(1);
  444.         installDefaultEventHandler();
  445.  
  446.     }
  447.  
  448.     /**
  449.      * Constructs a Grid using the specified DataSource instance.  If the
  450.      * DataSource supports meta data then it will be used to setup the Grid.
  451.      * @param ds The DataSource used to keep the Grid's data
  452.      */
  453.     public Grid(DataSource ds) {
  454.         dataSource = ds;
  455.         dataSource.setDefaultData();
  456.         assignDefaults();
  457.         dataSource.setGrid(this);
  458.         if (dataSource.supportsMeta()) {
  459.             try { dataSource.setupGrid(this); } catch(Exception e) {
  460.                 e.printStackTrace();
  461.             }
  462.         }
  463.     }
  464.  
  465.     boolean guiConstructed = false;
  466.  
  467.     void assignDefaults() {
  468.         initDefaults();
  469.         if (!guiConstructed) {
  470.             String osName = System.getProperty("os.name");
  471.             if (osName.regionMatches(true, 0, "Sol", 0, 3) ||
  472.                 osName.regionMatches(true, 0, "Sun", 0, 3)) {
  473.                 onSolaris = true;
  474.                 button = new Button("Button Solaris");
  475.                  add(button);
  476.                  button.setBackground(Color.lightGray);
  477.             }
  478.             // redrawer.start();
  479.             setLayout(new BorderLayout());
  480.             setFont(CellHints.stdFont);
  481.             setBackground(Color.white);
  482.             setForeground(Color.black);
  483.             vsb = new Scrollbar(Scrollbar.VERTICAL);
  484.             vsb.hide();
  485.  
  486.               toolbar = new Panel();
  487.                toolbar.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
  488.                toolbar.setBackground(Color.lightGray);
  489.  
  490.             hsb  = new Scrollbar(Scrollbar.HORIZONTAL);
  491.             Canvas pad = new Canvas();
  492.             pad.resize(vsb.preferredSize().width, hsb.preferredSize().height);
  493.             bottomPanel = new Panel();
  494.             bottomPanel.setBackground(Color.lightGray);
  495.             bottomPanel.setLayout(new BorderLayout());
  496.             bottomPanel.add("West", toolbar);
  497.             Panel padding = new Panel();
  498.             padding.setLayout(new BorderLayout());
  499.             padding.add("North", hsb);
  500.             bottomPanel.add("Center", padding);
  501.             bottomPanel.add("East", pad);
  502.  
  503.             add("East",vsb);
  504.             add("South", bottomPanel);
  505.  
  506.             guiConstructed = true;
  507.         }
  508.  
  509.         hints = new CellHints(this);
  510.         defaultCell = new BasicCell(this, dataSource);
  511.         defaultCell.setCoordinates(new Coordinate(0, 0));
  512.         defaultCell.setDefaultFlag();
  513.         headingHeight = getFontMetrics(CellHints.stdFont).getHeight() + 4;
  514.         cellHeight = headingHeight;
  515.  
  516.         cells = new Matrix();
  517.         colHeadings = new Matrix();
  518.         cellAttributes = new Matrix();      //cell hints
  519.         headingAttributes = new Matrix();   //col heading hints
  520.         headingSource = new DefaultDataSource(this);
  521.         rowHeadingSource = new DefaultDataSource(this, true);
  522.         rowHeadingHints = new CellHints(this);
  523.         setCornerCell(defaultHeadingCell_);
  524.         setDefaultRowHeadingCell(defaultHeadingCell_);
  525.         try {
  526.             rowHeadingSource.setData(0, 1, new ImageStringData(dataSource, ""));
  527.             rowHeadingSource.setDefaultData(new ImageStringData(dataSource));
  528.         } catch(TypeNotSupported ex) {}
  529.     }
  530.  
  531.     /**
  532.      * Sets the DataSource for keeping the Grid's data.  Replaces the previous
  533.      * DataSource if previously set.
  534.      * @param ds The DataSource to keep the Grid's data.
  535.      */
  536.     public /* synchronized */ void setDataSource(DataSource ds) {
  537.         clear();
  538.         dataSource = ds;
  539.         dataSource.setDefaultData();
  540.         assignDefaults();
  541.         dataSource.setGrid(this);
  542.         if (dataSource.supportsMeta()) {
  543.             try { dataSource.setupGrid(this); } catch(Exception e) {
  544.                 e.printStackTrace();
  545.             }
  546.         }
  547.     }
  548.  
  549.     /**
  550.      * Gets the DataSource for keeping the Grid's data.
  551.      */
  552.     public DataSource getDataSource() {
  553.         return dataSource;
  554.     }
  555.  
  556.     /**
  557.      * Sets the automatic redraw behavior of the Grid.  If auto redraw is
  558.      * turned on then adding rows or changing data will cause the grid to
  559.      * automatically redraw.  Turning it off can improve performance when
  560.      * making many changes at one time.
  561.      * @param redraw true to turn on automatic redrawing
  562.      */
  563.     public void setAutoRedraw(boolean redraw) {
  564.         autoRedraw = redraw;
  565.     }
  566.  
  567.     /**
  568.      * Gets the automatic redrawing setting.
  569.      */
  570.     public boolean getAutoRedraw() {
  571.         return autoRedraw;
  572.     }
  573.  
  574.     /**
  575.      * Installs the Grid's default event handler used to handle cell and
  576.      * table level events and perform actions required when exception occur.
  577.      */
  578.     public void installDefaultEventHandler() {
  579.         installEventHandler(new DefaultTvEventHandler());
  580.     }
  581.  
  582.     /**
  583.      * Installs an event handler used to handle cell and
  584.      * table level events and perform actions required when exception occur.
  585.      */
  586.     public void installEventHandler(TvEventHandler h) {
  587.         eventHandler = h;
  588.         eventHandler.setupView(this);
  589.     }
  590.  
  591.     /**
  592.      * Adds an add button to the Grid's toolbar.
  593.      */
  594.     public void addAppendButton() {
  595.         addToolbarButton(appendRowLabel);
  596.     }
  597.  
  598.     /**
  599.      * Adds an add button to the Grid's toolbar with the specified label.
  600.      */
  601.     public void addAppendButton(String label) {
  602.         removeAppendButton();
  603.         appendRowLabel = label;
  604.         addToolbarButton(label);
  605.     }
  606.  
  607.     /**
  608.      * Removes the add button from the toolbar.
  609.      */
  610.     public void removeAppendButton() {
  611.         removeToolbarButton(appendRowLabel);
  612.     }
  613.  
  614.     /**
  615.      * Adds an insert button to the Grid's toolbar.
  616.      */
  617.     public void addInsertButton() {
  618.         addToolbarButton(insertRowLabel);
  619.     }
  620.  
  621.     /**
  622.      * Adds an insert button to the Grid's toolbar.
  623.      */
  624.     public void addInsertButton(String label) {
  625.         removeInsertButton();
  626.         insertRowLabel = label;
  627.         addToolbarButton(label);
  628.     }
  629.  
  630.     /**
  631.      * Removes the insert button to the Grid's toolbar.
  632.      */
  633.     public void removeInsertButton() {
  634.         removeToolbarButton(insertRowLabel);
  635.     }
  636.  
  637.     /**
  638.      * Adds a delete button to the Grid's toolbar.
  639.      */
  640.     public void addDeleteButton() {
  641.         addToolbarButton(deleteRowLabel);
  642.     }
  643.  
  644.     /**
  645.      * Adds a delete button to the Grid's toolbar with the specified label.
  646.      */
  647.     public void addDeleteButton(String label) {
  648.         removeDeleteButton();
  649.         deleteRowLabel = label;
  650.         addToolbarButton(label);
  651.     }
  652.  
  653.     /**
  654.      * Removes the delete button to the Grid's toolbar.
  655.      */
  656.     public void removeDeleteButton() {
  657.         removeToolbarButton(deleteRowLabel);
  658.     }
  659.  
  660.     /**
  661.      * Adds a save button to the Grid's toolbar.
  662.      */
  663.     public void addSaveButton() {
  664.         addToolbarButton(saveLabel);
  665.     }
  666.  
  667.     /**
  668.      * Adds a save button to the Grid's toolbar with the specified label.
  669.      */
  670.     public void addSaveButton(String label) {
  671.         removeSaveButton();
  672.         saveLabel = label;
  673.         addToolbarButton(label);
  674.     }
  675.  
  676.     /**
  677.      * Removes the save button to the Grid's toolbar.
  678.      */
  679.     public void removeSaveButton() {
  680.         removeToolbarButton(saveLabel);
  681.     }
  682.  
  683.     /**
  684.      * Adds a restart button to the Grid's toolbar.
  685.      */
  686.     public void addRestartButton() {
  687.         addToolbarButton(restartLabel);
  688.     }
  689.  
  690.     /**
  691.      * Adds a restart button to the Grid's toolbar with the specified label.
  692.      */
  693.     public void addRestartButton(String label) {
  694.         removeRestartButton();
  695.         restartLabel = label;
  696.         addToolbarButton(label);
  697.     }
  698.  
  699.     /**
  700.      * Removes the restart button to the Grid's toolbar.
  701.      */
  702.     public void removeRestartButton() {
  703.         removeToolbarButton(restartLabel);
  704.     }
  705.  
  706.     /**
  707.      * Adds a delete button to the Grid's toolbar.
  708.      */
  709.     public void addUndeleteButton() {
  710.         addToolbarButton(undeleteRowLabel);
  711.     }
  712.  
  713.     /**
  714.      * Adds a delete button to the Grid's toolbar with the specified label.
  715.      */
  716.     public void addUndeleteButton(String label) {
  717.         removeUndeleteButton();
  718.         undeleteRowLabel = label;
  719.         addToolbarButton(label);
  720.     }
  721.  
  722.     /**
  723.      * Removes the delete button to the Grid's toolbar.
  724.      */
  725.     public void removeUndeleteButton() {
  726.         removeToolbarButton(undeleteRowLabel);
  727.     }
  728.  
  729.     /**
  730.      * Removes the undo button to the Grid's toolbar.
  731.      */
  732.     public void addUndoButton() {
  733.         addToolbarButton(undoRowLabel);
  734.     }
  735.  
  736.     /**
  737.      * Adds a undo button to the Grid's toolbar with the specified label.
  738.      */
  739.     public void addUndoButton(String label) {
  740.         removeUndoButton();
  741.         undoRowLabel = label;
  742.         addToolbarButton(label);
  743.     }
  744.  
  745.     /**
  746.      * Removes the undo button to the Grid's toolbar.
  747.      */
  748.     public void removeUndoButton() {
  749.         removeToolbarButton(undoRowLabel);
  750.     }
  751.  
  752.  
  753.     Panel gotoPanel;
  754.     java.awt.TextField gotoTextField;
  755.     Button gotoButton;
  756.  
  757.     /**
  758.      * Add a goto button to the Grid's toolbar.
  759.      */
  760.     public void addGotoButton() {
  761.         if (gotoPanel == null) {
  762.             gotoPanel = new Panel();
  763.             gotoPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0));
  764.             gotoPanel.add(gotoButton = new Button(gotoRowLabel));
  765.             gotoPanel.add(gotoTextField = new java.awt.TextField(4));
  766.         } else {
  767.             return;
  768.         }
  769.  
  770.         addToToolbar(gotoPanel);
  771.     }
  772.  
  773.     /**
  774.      * Removes the goto button to the Grid's toolbar.
  775.      */
  776.     public void removeGotoButton() {
  777.         if (gotoPanel == null) {
  778.             return;
  779.         } else {
  780.             removeFromToolbar(gotoPanel);
  781.             gotoPanel = null;
  782.         }
  783.     }
  784.  
  785.     /**
  786.      * Adds a button to the Grid's toolbar using the specified label.
  787.      */
  788.     public void addToolbarButton(String label) {
  789.         Enumeration e = toolbarComponents.elements();
  790.         Component c;
  791.  
  792.         while(e.hasMoreElements()) {
  793.             c = (Component)e.nextElement();
  794.             if (c instanceof Button && ((Button)c).getLabel().equals(label)) {
  795.                 return;
  796.             }
  797.         }
  798.  
  799.         addToToolbar(new Button(label));
  800.     }
  801.  
  802.     /**
  803.      * Removes a button to the Grid's toolbar using the specified label.
  804.      */
  805.     public void removeToolbarButton(String label) {
  806.         Enumeration e = toolbarComponents.elements();
  807.         Component c;
  808.  
  809.         while(e.hasMoreElements()) {
  810.             c = (Component)e.nextElement();
  811.             if (c instanceof Button && ((Button)c).getLabel().equals(label)) {
  812.                 toolbarComponents.removeElement(c);
  813.                 return;
  814.             }
  815.         }
  816.     }
  817.  
  818.     /**
  819.      * Returns whether the specified component is located on the toolbar
  820.      * @param c The component to check the toolbar for containment
  821.      */
  822.     public boolean isToolbarComponent(Object c) {
  823.         return toolbarComponents.contains(c) || c == gotoTextField || c == gotoButton;
  824.     }
  825.  
  826.     /**
  827.      * Adds a component to the toolbar
  828.      * @param c The component to add
  829.      */
  830.     public void addToToolbar(Component c) {
  831.         toolbarComponents.addElement(c);
  832.         toolbar.add(c);
  833.     }
  834.  
  835.     /**
  836.      * Removes an item from the toolbar
  837.      */
  838.     public void removeFromToolbar(Component c) {
  839.         toolbarComponents.removeElement(c);
  840.         toolbar.remove(c);
  841.     }
  842.  
  843.     /**
  844.      * Sets whether the last column should be filled to the end of the visible
  845.      * space of the grid
  846.      */
  847.     public void setFillLastColumn(boolean fill) {
  848.         fillLastColumn = fill;
  849.     }
  850.  
  851.     /**
  852.      * Gets whether the last column should be filled to the end of the visible
  853.      * space of the grid
  854.      */
  855.     public boolean getFillLastColumn() {
  856.         return fillLastColumn;
  857.     }
  858.  
  859.     /**
  860.      * Set heading text and width.  Only button styles are supported.
  861.      * @param h string for heading text
  862.      * @param col number of column (one relative)
  863.      * @param chars width of column in characters
  864.      */
  865.     public void setHeading(String h, int col, int chars) {
  866.         ButtonCell cell = new ButtonCell(1, col);
  867.         cell.type(TableCell.COL_HEADING);
  868.         cell.setGrid(this, headingSource);
  869.         colHeadings.updateElement(0, col-1, cell);
  870.         try {
  871.             headingSource.setData(cell.getCoordinates(),
  872.                                   new ImageStringData(dataSource, h));
  873.         } catch(TypeNotSupported ex) {}
  874.         setHeadingSize(col, chars);
  875.         if (autoRedraw) {
  876.             redrawAsync();
  877.         }
  878.     }
  879.  
  880.     /**
  881.      * Set column width of a column.
  882.      * @param col column number to set width
  883.      * @param chars width of column in characters
  884.      */
  885.     public /* synchronized */ void setHeadingSize(int col, int chars) {
  886.         CellHints hints = getHeadingHints(0, col);
  887.         int width = getFontMetrics(hints.font).charWidth('W') * chars;
  888.         resizeColumn(col, splitters[col-1] + width);
  889.     }
  890.  
  891.     /**
  892.      * Sets the preferred row count. Used to determine the preferred size
  893.      */
  894.      public void setPreferredRowCount(int c) { preferredRowCount = c; }
  895.  
  896.     /**
  897.      * Gets the preferred row count. Used to determine the preferred size
  898.      */
  899.      public int getPreferredRowCount() { return preferredRowCount; }
  900.  
  901.     /**
  902.      * Returns the preferred size of this component.
  903.      * @see #minimumSize
  904.      */
  905.     public Dimension preferredSize() {
  906.         int w=0, h=0;
  907.         w = splitters[splitters.length-1] + rowHeadingWidth;
  908.         h = (preferredRowCount + 1) * cellHeight;
  909.  
  910.         Dimension toolsize = toolbar.size();
  911.         return new Dimension(Math.max(w, toolsize.width),
  912.                              h + toolsize.height);
  913.     }
  914.  
  915.     /**
  916.      * Returns the minimum size of this component.
  917.      * @see #preferredSize
  918.      * @see LayoutManager
  919.      */
  920.     public Dimension minimumSize() {
  921.         return preferredSize();
  922.     }
  923.  
  924.     /**
  925.      * Create specified number of columns for Grid.
  926.      * @param i number of columns for MulitList
  927.      */
  928.     public /* synchronized */ void createColumns(int i) {
  929.         dataSource.clear();
  930.  
  931.         //set the corner cell hints
  932.           headingAttributes.addElement(0, 0, new CellHints(this));
  933.  
  934.         //set cell and heading hints
  935.         for(int col=1;col<=i;col++) {
  936.             cellAttributes.addElement(0, col, new CellHints(this));
  937.             headingAttributes.addElement(0, col, new CellHints(this));
  938.         }
  939.  
  940.         splitters = new int[i+1];
  941.     }
  942.  
  943. //-----------------------------------------------------------------------------
  944. //                          Heading APIs
  945. //-----------------------------------------------------------------------------
  946.  
  947.     /**
  948.      * Sets the cell to be used by the corner cell.  The corner cell is in
  949.      * the upper left and is only visible if row headings are present.
  950.      */
  951.     public /* synchronized */ void setCornerCell(TableCell c) {
  952.         cornerCell = c.cloneCell();
  953.         cornerCell.setGrid(this, rowHeadingSource);
  954.         cornerCell.setCoordinates(new Coordinate(0, 1));
  955.         cornerCell.type(TableCell.CORNER_CELL);
  956.     }
  957.  
  958.     /**
  959.      * Sets the cell type used to display the row headings.  All row headings
  960.      * must be of the same type.
  961.      */
  962.     public /* synchronized */ void setDefaultRowHeadingCell(TableCell c) {
  963.         headingCell = c.cloneCell();
  964.         headingCell.setGrid(this, rowHeadingSource);
  965.     }
  966.  
  967.     /**
  968.      * Sets the width of the row headings
  969.      */
  970.     public /* synchronized */ void setRowHeadingWidth(int w) {
  971.         rowHeadingWidth = w;
  972.     }
  973.  
  974.     /**
  975.      * Gets the width of the row headings
  976.      */
  977.     public /* synchronized */ int getRowHeadingWidth(int w) {
  978.         return rowHeadingWidth;
  979.     }
  980.  
  981.     /**
  982.      * Sets whether row headings should be displayed.
  983.      */
  984.     public void useRowHeadings(boolean use) {
  985.         rowHeadingHints.visible = use;
  986.     }
  987.  
  988.     /**
  989.      * Gets whether row headings should be displayed.
  990.      */
  991.     public boolean isUsingRowHeadings() {
  992.         return rowHeadingHints.visible;
  993.     }
  994.  
  995.     /**
  996.      * Sets the display height of cells.
  997.      */
  998.     public /* synchronized */ void setCellHeight(int h) {
  999.         int stdHeight = getFontMetrics(CellHints.stdFont).getHeight() + 4;
  1000.  
  1001.         if (h < stdHeight) {
  1002.             cellHeight = stdHeight;
  1003.         } else {
  1004.             cellHeight = h;
  1005.         }
  1006.  
  1007.         if (autoRedraw) {
  1008.             redrawAsync();
  1009.         }
  1010.     }
  1011.  
  1012.     /**
  1013.      * Sets the row heading style.
  1014.      * @param s The style and must be one of BLANK or AUTONUMBER
  1015.      */
  1016.     public /* synchronized */ void setRowLabelHeadingStyle(int s) {
  1017.         if (s < AUTONUMBER || s > USER_DEFINED) {
  1018.             throw new IllegalArgumentException("Illegal heading label style");
  1019.         }
  1020.  
  1021.         rowHeadingLabelStyle = s;
  1022.         if (s == AUTONUMBER) {
  1023.              rowHeadingSource.doAutoNumbering(true);
  1024.         } else {
  1025.              rowHeadingSource.doAutoNumbering(false);
  1026.         }
  1027.     }
  1028.  
  1029.     /**
  1030.      * Gets the number of the first row in the Grid
  1031.      */
  1032.     public int getFirstAutoNumber() {
  1033.         return rowHeadingWidth;
  1034.     }
  1035.  
  1036.     /**
  1037.      * Causes row headings to be visible displaying row numbers starting with
  1038.      * the specified value.
  1039.      * @param first The number of the first row
  1040.      */
  1041.     public void setupAutonumbering(int first) {
  1042.         setupAutonumbering(first, rowHeadingWidth);
  1043.     }
  1044.  
  1045.     /**
  1046.      * Causes row headings to be visible displaying row numbers starting with
  1047.      * the specified value and sets the row headings to a fixed width to start.
  1048.      * @param first The number of the first row
  1049.      * @param pixels The starting width of the row headings
  1050.      */
  1051.     public /* synchronized */ void setupAutonumbering(int first, int pixels) {
  1052.         rowHeadingLabelStyle = AUTONUMBER;
  1053.         rowHeadingSource.doAutoNumbering(true, first);
  1054.         rowHeadingHints.visible = true;
  1055.         rowHeadingWidth = pixels;
  1056.     }
  1057.  
  1058.     /**
  1059.      * Sets the default value used when the row headings do not contain
  1060.      * data for the row
  1061.      */
  1062.     public /* synchronized */ void setDefaultRowData(String s) {
  1063.         rowHeadingSource.setDefaultData(new ImageStringData(dataSource, s));
  1064.     }
  1065.  
  1066.     /**
  1067.      * Sets the default data used when the row headings do not contain
  1068.      * data for the row
  1069.      */
  1070.     public /* synchronized */ void setDefaultRowData(Data d) {
  1071.         rowHeadingSource.setDefaultData(d);
  1072.     }
  1073.  
  1074.     /**
  1075.      * Sets the row heading label alignment style.
  1076.      * @param a The alignment style: LEFT, CENTER, RIGHT
  1077.      */
  1078.     public /* synchronized */ void setRowHeadingAlignment(int a) {
  1079.         if (a < LEFT || a > RIGHT) {
  1080.             throw new IllegalArgumentException("Illegal alignment style");
  1081.         }
  1082.  
  1083.         rowHeadingHints.align = a;
  1084.     }
  1085.  
  1086.     /**
  1087.      * Gets the row heading label style
  1088.      * @return The alignment style: LEFT, CENTER, RIGHT
  1089.      */
  1090.     public int getRowLabelHeadingStyle() {
  1091.         return rowHeadingLabelStyle;
  1092.     }
  1093.  
  1094.     /**
  1095.      * Gets the row heading alignment style
  1096.      * @return The alignment style: LEFT, CENTER, RIGHT
  1097.      */
  1098.     public int getRowHeadingAlignment() {
  1099.         return rowHeadingHints.align;
  1100.     }
  1101.  
  1102.     /**
  1103.      * Gets column heading text of specified column.
  1104.      */
  1105.     public String getHeading(int col) {
  1106.         return cells.elementAt(-1, col).toString();
  1107.     }
  1108.  
  1109.     /**
  1110.      * Set the font of the column heading text.
  1111.      * @param f font instance for heading text.
  1112.      * @param col the heading column to set (1 relative).
  1113.      */
  1114.     public /* synchronized */ void setHeadingFont(Font f, int col) {
  1115.         CellHints hints = getHeadingHints(0, col);
  1116.         hints.font = f;
  1117.         headingHeight = getFontMetrics(f).getHeight();
  1118.         if (autoRedraw) { redrawAsync(); }
  1119.     }
  1120.     /**
  1121.      * Returns the font of the column heading text
  1122.      * @param col the heading column to get (1 relative).
  1123.      */
  1124.     public Font getHeadingFont(int col) {
  1125.         return getHeadingHints(0, col).font();
  1126.     }
  1127.  
  1128.  
  1129. //-----------------------------------------------------------------------------
  1130. //                          Cell Control APIs
  1131. //-----------------------------------------------------------------------------
  1132.  
  1133.  
  1134.     /**
  1135.      * Gets the cell that currently possesses the keyboard focus.<p>
  1136.      * WARNING: This is shared data - Do not hold onto this past current call!!
  1137.      * @return The TableCell that has the keyboard focus.
  1138.      */
  1139.     public TableCell getCurrentCell() {
  1140.         return currSelectedCell;
  1141.     }
  1142.  
  1143.     /**
  1144.      * Gets the data for the cell that currently has the keyboard focus.<p>
  1145.      * WARNING: This is shared data - Do not hold onto this past current call!!
  1146.      * @return The Data instance for the cell that has the keyboard focus.
  1147.      * @exception   DataNotAvailable If the DataSource does not currently have
  1148.      *      data for the cell
  1149.      */
  1150.     public Data getCurrentCellData() throws DataNotAvailable {
  1151.         if (currSelectedCell == null) return null;
  1152.  
  1153.         return dataSource.getData(currSelectedCell.getCoordinates());
  1154.     }
  1155.  
  1156.     /**
  1157.      * Gets the coordinate of the cell that has the keyboard focus
  1158.      */
  1159.     public Coordinate getCurrentCellCoordinates() {
  1160.         if (currSelectedCell == null) return null;
  1161.         Coordinate c =  currSelectedCell.getCoordinates();
  1162.  
  1163.         //make one relative
  1164.         return new Coordinate(c.row()+1, c.col()+1);
  1165.     }
  1166.  
  1167.     /**
  1168.      * Ensures that no cell is marked as the current cell for editing
  1169.      */
  1170.     public /* synchronized */ void clearCurrentCell() {
  1171.         if (currSelectedCell == null) {
  1172.             return;
  1173.         }
  1174.  
  1175.         sendFocusEvents(currSelectedCell, null);
  1176.     }
  1177.  
  1178.     /**
  1179.      * Sets the cell that has the keyboard focus to the one at the specified
  1180.      * row and column
  1181.      */
  1182.     public /* synchronized */ void setCurrentCell(int row, int col) {
  1183.         row--;
  1184.         col--;
  1185.  
  1186.         TableCell newSelection = null;
  1187.         if (currSelectedCell == null || row != currSelectedCell.row() ||
  1188.             col != currSelectedCell.col())
  1189.         {
  1190.             if (!cells.contains(row, col)) {
  1191.                 if (row < 0 || !validRow(row)
  1192.                     || col < 0 || col >= getNumberOfCols())
  1193.                 {
  1194.                     //row and/or column not valid
  1195.                     return;
  1196.                 }
  1197.  
  1198.                 //then we need to use the default cell
  1199.                   newSelection = getUniqueCell(row, col);
  1200.             } else {
  1201.                 newSelection = (TableCell)cells.elementAt(row, col);
  1202.             }
  1203.  
  1204.             sendFocusEvents(currSelectedCell, newSelection);
  1205.         }
  1206.     }
  1207.  
  1208.     /**
  1209.      * Sets the background color for a column
  1210.      */
  1211.     public /* synchronized */ void setColBgColor(int col, Color bg) {
  1212.         CellHints h = getColHints(col-1);
  1213.         h.bg = bg;
  1214.     }
  1215.  
  1216.     /**
  1217.      * Sts the background color for a row
  1218.      */
  1219.     public /* synchronized */ void setRowBgColor(int row, Color bg) {
  1220.         row--;
  1221.  
  1222.         CellHints h = getRowHints(row);
  1223.         if (h == null) {
  1224.             h = new CellHints(this);
  1225.             addRowHint(row,  h);
  1226.         }
  1227.  
  1228.         h.set(CellHints.BG_BIT);
  1229.         h.bg = bg;
  1230.     }
  1231.  
  1232.     /**
  1233.      * Sets the background color for a cell
  1234.      */
  1235.     public /* synchronized */ void setCellBgColor(int row, int col, Color bg) {
  1236.         row--; col--;
  1237.  
  1238.         CellHints h = getCellHints(row, col);
  1239.         if (h == null) {
  1240.             h = new CellHints(this);
  1241.             addCellHint(row, col, h);
  1242.         }
  1243.  
  1244.         h.set(CellHints.BG_BIT);
  1245.         h.bg = bg;
  1246.     }
  1247.  
  1248.     /**
  1249.      * Sets the foreground color for a column
  1250.      */
  1251.     public /* synchronized */ void setColFgColor(int col, Color fg) {
  1252.         CellHints h = getColHints(col-1);
  1253.         h.fg = fg;
  1254.     }
  1255.  
  1256.     /**
  1257.      * Sets the foreground color for a row
  1258.      */
  1259.     public /* synchronized */ void setRowFgColor(int row, Color fg) {
  1260.         row--;
  1261.  
  1262.         CellHints h = getRowHints(row);
  1263.         if (h == null) {
  1264.             h = new CellHints(this);
  1265.             addRowHint(row,  h);
  1266.         }
  1267.  
  1268.         h.set(CellHints.FG_BIT);
  1269.         h.fg = fg;
  1270.     }
  1271.  
  1272.     /**
  1273.      * Sets the foreground color for a cell
  1274.      */
  1275.     public /* synchronized */ void setCellFgColor(int row, int col, Color fg) {
  1276.         row--; col--;
  1277.  
  1278.         CellHints h = getCellHints(row, col);
  1279.         if (h == null) {
  1280.             h = new CellHints(this);
  1281.             addCellHint(row, col, h);
  1282.         }
  1283.  
  1284.         h.set(CellHints.FG_BIT);
  1285.         h.fg = fg;
  1286.     }
  1287.  
  1288.    /**
  1289.      * Set the font of for a column.
  1290.      * @param col the column to set the font
  1291.      * @param f font instance for cell text
  1292.      */
  1293.     public /* synchronized */ void setColFont(int col, Font f) {
  1294.         CellHints h = getColHints(col);
  1295.         h.font = f;
  1296.         cellHeight = getFontMetrics(f).getHeight() + 4;
  1297.         if (autoRedraw) { redrawAsync(); }
  1298.     }
  1299.  
  1300.    /**
  1301.      * Set the font of for a row.
  1302.      * @param row the row to set the font
  1303.      * @param f font instance for cell text
  1304.      */
  1305.     public /* synchronized */ void setRowFont(int row, Font f) {
  1306.         row--;
  1307.  
  1308.         CellHints h = getRowHints(row);
  1309.         if (h == null) {
  1310.             h = new CellHints(this);
  1311.             addRowHint(row,  h);
  1312.         }
  1313.  
  1314.         h.set(CellHints.FONT_BIT);
  1315.         h.font = f;
  1316.     }
  1317.  
  1318.    /**
  1319.      * Set the font of for a cell.
  1320.      */
  1321.     public /* synchronized */ void setCellFont(int row, int col, Font f) {
  1322.         row--; col--;
  1323.  
  1324.         CellHints h = getCellHints(row, col);
  1325.         if (h == null) {
  1326.             h = new CellHints(this);
  1327.             addCellHint(row, col, h);
  1328.         }
  1329.  
  1330.         h.set(CellHints.FONT_BIT);
  1331.         h.font = f;
  1332.     }
  1333.  
  1334.     /**
  1335.       * Returns the current font setting for cell text.
  1336.       */
  1337.     public Font getColFont(int col) {
  1338.         col--;
  1339.         return getColHints(col).font();
  1340.     }
  1341.  
  1342.     /**
  1343.      * Sets whether the cells in a column may be edited
  1344.      */
  1345.     public /* synchronized */ void setColEditable(int col, boolean edit) {
  1346.         // align must be LEFT, CENTER, or RIGHT
  1347.         CellHints h = getColHints(col-1);
  1348.         h.editable = edit;
  1349.     }
  1350.  
  1351.     /**
  1352.      * Sets whether the cells in a row may be edited
  1353.      */
  1354.      public /* synchronized */ void setRowEditable(int row, boolean edit) {
  1355.         row--;
  1356.  
  1357.         CellHints h = getRowHints(row);
  1358.         if (h == null) {
  1359.             h = new CellHints(this);
  1360.             addRowHint(row,  h);
  1361.         }
  1362.  
  1363.         h.set(CellHints.EDITABLE_BIT);
  1364.         h.editable = edit;
  1365.     }
  1366.  
  1367.     /**
  1368.      * Sets whether a cell can be edited
  1369.      */
  1370.     public /* synchronized */ void setCellEditable(int row, int col, boolean edit) {
  1371.         row--; col--;
  1372.  
  1373.         CellHints h = getCellHints(row, col);
  1374.         if (h == null) {
  1375.             h = new CellHints(this);
  1376.             addCellHint(row, col, h);
  1377.         }
  1378.  
  1379.         h.set(CellHints.EDITABLE_BIT);
  1380.         h.editable = edit;
  1381.     }
  1382.  
  1383.     /**
  1384.      * Clears the CellHints for a cell
  1385.      */
  1386.     public /* synchronized */ void clearCellHint(int row, int col, int bit) {
  1387.         row--; col--;
  1388.  
  1389.         CellHints h = getCellHints(row, col);
  1390.         if (h != null) {
  1391.             h.clear(bit);
  1392.         }
  1393.     }
  1394.  
  1395.     /**
  1396.      * Clears the CellHints for a row
  1397.      */
  1398.     public /* synchronized */ void clearRowHint(int row, int bit) {
  1399.         row--;
  1400.  
  1401.         CellHints h = getRowHints(row);
  1402.         if (h != null) {
  1403.             h.clear(bit);
  1404.         }
  1405.     }
  1406.  
  1407.     /**
  1408.      * Gets whether CellHints a set for a particular cell.
  1409.      * @param row The cell row
  1410.      * @param col The cell column
  1411.      * @param bit The particular variable of the hint that is of interest as
  1412.      *      defined in CellHints
  1413.      */
  1414.     public boolean isCellHintSet(int row, int col, int bit) {
  1415.         row--; col--;
  1416.  
  1417.         CellHints h = getCellHints(row, col);
  1418.         if (h != null) {
  1419.             return h.get(bit);
  1420.         }
  1421.  
  1422.         return false;
  1423.     }
  1424.  
  1425.     /**
  1426.      * Gets whether CellHints a set for a particular row.
  1427.      * @param row The cell row
  1428.      * @param bit The particular variable of the hint that is of interest as
  1429.      *      defined in CellHints
  1430.      */
  1431.     public boolean isRowHintSet(int row, int bit) {
  1432.         row--;
  1433.  
  1434.         CellHints h = getRowHints(row);
  1435.         if (h != null) {
  1436.             return h.get(bit);
  1437.         }
  1438.  
  1439.         return false;
  1440.     }
  1441.  
  1442.     /**
  1443.      * Gets whether CellHints a set for a particular column.
  1444.      * @param col The cell column
  1445.      * @param bit The particular variable of the hint that is of interest as
  1446.      *      defined in CellHints
  1447.      */
  1448.     public boolean getColEditable(int col) {
  1449.         col--;
  1450.         return getColHints(col).editable();
  1451.     }
  1452.  
  1453.     /**
  1454.      * Sets whether the column heading of interest is editable.
  1455.      */
  1456.     public /* synchronized */ void setHeadingEditable(int col, boolean edit) {
  1457.         CellHints h = getHeadingHints(0, col);
  1458.         h.editable = edit;
  1459.     }
  1460.  
  1461.     /**
  1462.      * Gets whether the column heading of interest is editable.
  1463.      */
  1464.     public boolean getHeadingEditable(int col) {
  1465.         return getHeadingHints(0, col).editable();
  1466.     }
  1467.  
  1468.     /**
  1469.      * Set the heading foreground and background colors of the heading hints
  1470.      * @fg foreground Color for heading text
  1471.      * @bg background Color for heading text
  1472.      */
  1473.     public /* synchronized */ void setHeadingColors(int col, Color fg, Color bg) {
  1474.         CellHints h = getHeadingHints(0, col);
  1475.         h.fg = fg;
  1476.         h.bg = bg;
  1477.         if (autoRedraw) { redrawAsync(); }
  1478.     }
  1479.  
  1480.     /**
  1481.      * Returns the color of the column heading foreground.
  1482.      */
  1483.     public Color getHeadingFg(int col) {
  1484.         CellHints h = getHeadingHints(0, col);
  1485.         return h.fg;
  1486.     }
  1487.  
  1488.     /**
  1489.      * Returns the color of the column heading background.
  1490.      */
  1491.     public Color getHeadingBg(int col) {
  1492.         CellHints h = getHeadingHints(0, col);
  1493.         return h.bg;
  1494.     }
  1495.  
  1496.     /**
  1497.      * Get the column size in pixels for the specified column.
  1498.      * @param i number of column (one relative)
  1499.      */
  1500.     public int getColumnSize(int i) {
  1501.         return getColumnWidth(i-1);
  1502.     }
  1503.  
  1504.     /**
  1505.      * Set the justification of the text for the specified column.
  1506.      * @param i number of column (one relative)
  1507.      * @param align one of the values LEFT, CENTER, or RIGHT
  1508.      */
  1509.     public /* synchronized */ void setColumnAlignment(int col, int align) {
  1510.         // align must be LEFT, CENTER, or RIGHT
  1511.         CellHints h = getColHints(col-1);
  1512.         h.align = align;
  1513.         h = getHeadingHints(0, col);
  1514.         h.align = align;
  1515.     }
  1516.  
  1517.     /**
  1518.      * Returns the current number of rows.
  1519.      */
  1520.     public int getNumberOfRows() {
  1521.         try {
  1522.             dataSource.fetchMode(true);
  1523.             return Math.max(cells.rows(), dataSource.fetchAllRows());
  1524.         } finally {
  1525.             dataSource.fetchMode(false);
  1526.         }
  1527.     }
  1528.  
  1529.     /**
  1530.      * Returns the current number of columns.
  1531.      */
  1532.     public int getNumberOfCols() {
  1533.         return splitters.length - 1;
  1534.     }
  1535.  
  1536.     /**
  1537.      * Ensures the topRow variable is valid
  1538.      */
  1539.     public void setTopRow() {
  1540.         setTopRow(-1);
  1541.     }
  1542.  
  1543.     /**
  1544.      * Sets the top row to be displayed when table is drawn.
  1545.      */
  1546.     public /* synchronized */ void setTopRow(int row) {
  1547.         //visible from outside so row is one relative
  1548.         if (row >= 1) {
  1549.             topRow = row-1;
  1550.         }
  1551.  
  1552.         try {
  1553.             int dataRows = dataSource.validDataRowRange(0, topRow+1);
  1554.  
  1555.             //using top row resulted in a valid range so we're done
  1556.             return;
  1557.         } catch(DataNotAvailable exc) {
  1558.             //no data so all up to cells
  1559.             if (topRow <= cells.rows()-1) {
  1560.                 //there are enough cells so everything is OK
  1561.                 return;
  1562.             }
  1563.  
  1564.             //Need to reset topRow to valid number so how about 0
  1565.             topRow = 0;
  1566.         }
  1567.     }
  1568.  
  1569.     /**
  1570.      * Gets the top row that is used when the Grid is drawn.<p>
  1571.      * WARNING: The value returned is 0 relative
  1572.      * @return The top row - 0 relative
  1573.      */
  1574.     public int getTopRow() {
  1575.         return topRow;
  1576.     }
  1577.  
  1578.     /**
  1579.      * Gets the actual number of rows being painted.
  1580.      */
  1581.     public int getNumberOfVisibleRows() {
  1582.         setTopRow();
  1583.         int count = (int)((height-3)/cellHeight) - 1;
  1584.  
  1585.         try {
  1586.             int dataRows = dataSource.validDataRowRange(topRow, topRow+count);
  1587.             int lastCellRow = cells.rows();
  1588.             count = Math.min(count, Math.max(dataRows, lastCellRow)-topRow+1);
  1589.         } catch(DataNotAvailable exc) {
  1590.             //no data so all up to cells
  1591.             if (count > cells.rows()) {
  1592.                 count = cells.rows()-topRow;
  1593.             }
  1594.         }
  1595.  
  1596.         // System.out.println("getNumberOfVisibleRows " + String.valueOf(count));
  1597.         return count;
  1598.     }
  1599.  
  1600.     /**
  1601.      * Sets the mouse capture to the currently selected cell.
  1602.      */
  1603.     public void setCapture() {
  1604.         if (rowHeadingCell(currCaptureCell) && currSelectedCell != currCaptureCell) {
  1605.             currHeadingCell = null;
  1606.         }
  1607.  
  1608.         currCaptureCell = currSelectedCell;
  1609.     }
  1610.  
  1611.     /**
  1612.      * Set mouse capture to a particular cell
  1613.      */
  1614.     public void setCapture(TableCell c) {
  1615.         if (rowHeadingCell(currCaptureCell) && c != currCaptureCell) {
  1616.             currHeadingCell = null;
  1617.         }
  1618.  
  1619.         currCaptureCell = c;
  1620.     }
  1621.  
  1622.     /**
  1623.      * Removes the mouse capture if a cell currently possess it.
  1624.      */
  1625.     public void lostCapture() {
  1626.         if (rowHeadingCell(currCaptureCell)) {
  1627.             currHeadingCell = null;
  1628.         }
  1629.  
  1630.         currCaptureCell = null;
  1631.     }
  1632.  
  1633.     /**
  1634.      * Gets whether a cell currently has mouse capture.
  1635.      */
  1636.     public boolean cellHasCapture() {
  1637.         return currCaptureCell != null;
  1638.     }
  1639.  
  1640.     /**
  1641.      * Remove all rows from the Grid.
  1642.      */
  1643.     public /* synchronized */ void clear() {
  1644.         clearAllSelections();
  1645.  
  1646.         cells.removeAllElements();
  1647.         if (dataSource != null) {
  1648.             dataSource.clear();
  1649.         }
  1650.  
  1651.         xDragLast = -1;
  1652.         isDragging = false;
  1653.         topRow = 0;
  1654.         leftCol = 1;
  1655.         vsb.setValue(0);
  1656.         hsb.setValue(0);
  1657.         currSelectedCell = currCaptureCell = null;
  1658.  
  1659.         if (autoRedraw) { redrawAsync(); }
  1660.     }
  1661.  
  1662.     /**
  1663.      * Adds a cell to the Grid
  1664.      * @param cell The cell to be displayed
  1665.      * @param s The value for the cell
  1666.      * @exception   TypeNotSupported If action is not supported by the DataSource
  1667.      */
  1668.     public /* synchronized */ void addCell(TableCell cell, String s) throws TypeNotSupported {
  1669.         cell = cell.cloneCell();
  1670.         cell.setGrid(this, dataSource);
  1671.         cells.updateElement(cell.row(), cell.col(), cell);
  1672.         dataSource.setData(cell.getCoordinates(),
  1673.                            new ImageStringData(dataSource, s));
  1674.         if (autoRedraw) { redrawAsync(); }
  1675.     }
  1676.  
  1677.     /**
  1678.      * Adds or changes the text of a row and column position.
  1679.      * @param r index of row
  1680.      * @param c index of column
  1681.      * @param s String text for cell
  1682.      * @exception   TypeNotSupported If action is not supported by the DataSource
  1683.      */
  1684.     public /* synchronized */ void addTextCell(int r, int c, String s) throws TypeNotSupported {
  1685.         r--; c--;
  1686.         dataSource.setData(r, c, new ImageStringData(dataSource, s));
  1687.  
  1688.         if (autoRedraw) {
  1689.             redrawAsync();
  1690.         }
  1691.     }
  1692.  
  1693.     /**
  1694.      * Adds or changes the image of a row and column position.
  1695.      * @param r index of row
  1696.      * @param c index of column
  1697.      * @param i image instance for cell
  1698.      * @exception   TypeNotSupported If action is not supported by the DataSource
  1699.      */
  1700.     public /* synchronized */ void addImageCell(int r, int c, Image i) throws TypeNotSupported {
  1701.         r--; c--;
  1702.         dataSource.setData(r, c, new ImageStringData(dataSource, i));
  1703.         if (autoRedraw) {
  1704.             redrawAsync();
  1705.         }
  1706.     }
  1707.  
  1708.     /**
  1709.      * Add/change contents of a cell, both text and image.
  1710.      * @param r index of row
  1711.      * @param c index of column
  1712.      * @parma s string text for cell
  1713.      * @param i image instance for cell
  1714.      * @exception   TypeNotSupported If action is not supported by the DataSource
  1715.      */
  1716.     public /* synchronized */ void addCell(int r, int c, String s, Image i) throws TypeNotSupported {
  1717.         r--; c--;
  1718.         dataSource.setData(r, c, new ImageStringData(dataSource, s, i));
  1719.         if (autoRedraw) {
  1720.             redrawAsync();
  1721.         }
  1722.     }
  1723.  
  1724.     /**
  1725.      * Gets string text of specified cell.
  1726.      * @param r index of row
  1727.      * @param c index of column
  1728.      * @exception   TypeNotSupported If action is not supported by the DataSource
  1729.      */
  1730.     public String getCellText(int r, int c) throws DataNotAvailable {
  1731.         r--; c--;
  1732.         return dataSource.getData(r, c).toString();
  1733.     }
  1734.  
  1735.  
  1736.     /**
  1737.      * Gets the data value for a specified cell
  1738.      * @param r index of row
  1739.      * @param c index of column
  1740.      * @exception   TypeNotSupported If action is not supported by the DataSource
  1741.      */
  1742.     public Data getCellData(int r, int c) throws DataNotAvailable {
  1743.         r--; c--;
  1744.         return dataSource.getData(r, c);
  1745.     }
  1746.  
  1747.    /**
  1748.     * Gets the FontMetrics for the specified cell
  1749.     */
  1750.    public FontMetrics getCellFontMetrics(TableCell c) {
  1751.         Font f = getCellFont(c);
  1752.         return getFontMetrics(f);
  1753.     }
  1754.  
  1755.  
  1756.     /**
  1757.      * Inherited from Component.
  1758.      */
  1759.     public void update(Graphics g) {
  1760.         paint(g);
  1761.     }
  1762.  
  1763.     void checkClipping(Graphics g) {
  1764.         Rectangle r = g.getClipRect();
  1765.         Dimension d = size();
  1766.  
  1767.         if (r.x != 0 || r.y != 0 ||
  1768.             r.width != d.width ||
  1769.             r.height != d.height) {
  1770.                 repaint();
  1771.         }
  1772.     }
  1773.  
  1774.     /**
  1775.      * Inherited from Component.
  1776.      */
  1777.     public /* synchronized */ void paint(Graphics g) {
  1778.         checkClipping(g);
  1779.         if ((width!=(size().width)) || (height!=size().height))  {
  1780.             redrawAsync();
  1781.         }
  1782.  
  1783.         if (im == null) { return; }
  1784.         g.drawImage(im, 0, 0, this);
  1785.     }
  1786.  
  1787.     /**
  1788.      * Inherited from Component.
  1789.      */
  1790.     public void addNotify() {
  1791.         super.addNotify();
  1792.         repaint();
  1793.     }
  1794.  
  1795.     void showScrollbars() {
  1796.         Dimension d = size(),
  1797.                   actualViewSize = new Dimension(),
  1798.                   reqdViewSize = new Dimension(),
  1799.                   hsbSize = bottomPanel.preferredSize(),
  1800.                   vsbSize = vsb.preferredSize();
  1801.         boolean   changed = false,
  1802.                   showVsb = false;
  1803.         int       reqdHeight = cells.rows();
  1804.  
  1805.         try {
  1806.             int dataRows = dataSource.validDataRowRange(0,getPageSize().height+2+topRow);
  1807.             reqdHeight = Math.max(reqdHeight, dataSource.rows());
  1808.         } catch(DataNotAvailable exc) {}
  1809.  
  1810.         actualViewSize.height = height - headingHeight - 3 - bottomPanel.size().height;
  1811.         actualViewSize.width = d.width;
  1812.         reqdViewSize.height = reqdHeight * cellHeight;
  1813.         reqdViewSize.width = splitters[splitters.length-1] + rowHeadingWidth;
  1814.  
  1815.         //check to see if horizontal scrollbar will be shown
  1816.         if (reqdViewSize.width > actualViewSize.width) {
  1817.             //definitely reqd
  1818.             actualViewSize.height -= hsbSize.height;
  1819.         } else if (reqdViewSize.width > actualViewSize.width - vsbSize.width) {
  1820.             //see if acutally need vertical scrollbar
  1821.             if (reqdViewSize.height > actualViewSize.height - hsbSize.height) {
  1822.                 //should need veritcal vsb and thus hsb scrollbar
  1823.                 actualViewSize.height -= hsbSize.height;
  1824.             }
  1825.         }
  1826.  
  1827.         //show vertical scrollbar if appropriate
  1828.         if (reqdViewSize.height > actualViewSize.height) {
  1829.             vsb.setValues(vsbPosition, getPageSize().height, 0, reqdHeight-1);
  1830.             vsb.setPageIncrement(getPageSize().height);
  1831.             vsb.show();
  1832.             changed = showVsb = true;
  1833.             actualViewSize.width -= vsbSize.width;
  1834.         } else {
  1835.             topRow = 0;
  1836.             vsb.hide();
  1837.             showVsb = false;
  1838.         }
  1839.  
  1840.         //show horizontal scrollbar if appropriate
  1841.         if (reqdViewSize.width > actualViewSize.width) {
  1842.             //determine what the last column completely visible is
  1843.             int i = 1;
  1844.             int row = 0, col = 0;
  1845.             if (currSelectedCell != null) {
  1846.                 Coordinate c = currSelectedCell.getCoordinates();
  1847.                 row = c.row;
  1848.                 col = c.col;
  1849.             }
  1850.  
  1851.             int shiftLeft = splitters[leftCol - 1] + rowHeadingWidth;
  1852.             for (;i<splitters.length; i++) {
  1853.                 if (splitters[i] - shiftLeft > actualViewSize.width) break;
  1854.             }
  1855.  
  1856.             if (vsb.isVisible()) {
  1857.                 actualViewSize.width -= vsb.size().width;
  1858.             }
  1859.  
  1860.             int sliderWidth = (int)((float)actualViewSize.width/reqdViewSize.width*getNumberOfCols());
  1861.             hsb.setValues(hsbPosition,
  1862.                          sliderWidth,
  1863.                          1,
  1864.                          splitters.length-1);
  1865.             hsb.setPageIncrement(sliderWidth);
  1866.             hsb.show();
  1867.             changed = true;
  1868.         } else {
  1869.             leftCol = 1;
  1870.             hsb.hide();
  1871.         }
  1872.  
  1873.         if (changed) {
  1874.             getParent().paintAll(getParent().getGraphics());
  1875.         }
  1876.     }
  1877.  
  1878.     /**
  1879.      * Inherited from Component.
  1880.      */
  1881.     public void show() {
  1882.         redrawAsync();
  1883.     }
  1884.  
  1885.     /**
  1886.      * Gets the column width of the specified column.
  1887.      */
  1888.     public int getColumnWidth(int col) {
  1889.         if (fillLastColumn && col == getNumberOfCols()-1) {
  1890.             return size().width - splitters[col] + 1;
  1891.         } else {
  1892.             return splitters[col+1] - splitters[col];
  1893.         }
  1894.     }
  1895.  
  1896.     boolean rowHeadingCell(TableCell cell) {
  1897.         return cell != null &&
  1898.                (cell == headingCell || cell == currHeadingCell
  1899.                 || cell.type() == TableCell.ROW_HEADING);
  1900.  
  1901.     }
  1902.  
  1903.     //returns zero relative column number for last column that is visible
  1904.     private int lastVisibleCol() {
  1905.         int width = size().width;
  1906.  
  1907.         for (int i=leftCol; i<splitters.length; i++) {
  1908.             if (splitters[i]-splitters[leftCol-1]>width) {
  1909.                 return Math.min(i, getNumberOfCols());
  1910.             }
  1911.         }
  1912.  
  1913.         return getNumberOfCols();
  1914.     }
  1915.  
  1916.     /**
  1917.      * Gets the bounding rectangle of a cell relative to the grid
  1918.      */
  1919.     public Rectangle getCellBounds(TableCell cell) {
  1920.         return getCellBounds(cell, null);
  1921.     }
  1922.  
  1923.     /**
  1924.      * Gets the bounding rectangle of a cell relative to the grid
  1925.      * @param cell The cell to fetch the bounds
  1926.      * @param b The rectangle object to place bounds in
  1927.      */
  1928.     public Rectangle getCellBounds(TableCell cell, Rectangle b) {
  1929.         Coordinate p = cell.getCoordinates();
  1930.  
  1931.         if (cell == cornerCell) {
  1932.             return new Rectangle(0, 0, rowHeadingWidth+1, headingHeight+2);
  1933.         } else if (rowHeadingCell(cell)) {
  1934.             return getRowHeadingBounds(cell, b);
  1935.         } else if (cell.type() == TableCell.COL_HEADING) {
  1936.             return getHeadingCellBounds(p, b);
  1937.         }
  1938.  
  1939.         return getCellBounds(p, b);
  1940.     }
  1941.  
  1942.     private Rectangle getCellBounds(Coordinate c, Rectangle b) {
  1943.         int shiftLeft = splitters[leftCol-1];
  1944.         int row = c.row;
  1945.         int col = c.col;
  1946.         int w = getColumnWidth(col);
  1947.         int left = splitters[col] - shiftLeft-1+rowHeadingWidth;
  1948.  
  1949.         if (leftCol-1 == col) { left++; }
  1950.         else { w++; }
  1951.  
  1952.         if (b == null) {
  1953.             b = new Rectangle();
  1954.         }
  1955.  
  1956.         if (w > width  - rowHeadingWidth) {
  1957.             w = width - rowHeadingWidth;
  1958.             if (vsb.isVisible()) { w -= vsb.size().width; }
  1959.         }
  1960.  
  1961.         b.reshape(left,
  1962.                   (row-topRow)*cellHeight + headingHeight + 2,
  1963.                   w,
  1964.                   cellHeight+1);
  1965.  
  1966.         return b;
  1967.     }
  1968.  
  1969.     /**
  1970.      * Gets the bounds of the column heading cell at the specified coordinate
  1971.      * @param coords The coordinates of the heading
  1972.      * @param b The rectangle to place the bounds values
  1973.      */
  1974.     public Rectangle getHeadingCellBounds(Coordinate coords, Rectangle b) {
  1975.         int shiftLeft = splitters[leftCol-1];
  1976.         int row = coords.row;
  1977.         int col = coords.col;
  1978.         int w = getColumnWidth(col);
  1979.         int left = splitters[col]-shiftLeft-1+rowHeadingWidth;
  1980.  
  1981.         if (col == 0) { left++; }
  1982.         else { w++; }
  1983.  
  1984.         if (b == null) {
  1985.             b = new Rectangle();
  1986.         }
  1987.  
  1988.         if (w > width  - rowHeadingWidth) {
  1989.             w = width - rowHeadingWidth;
  1990.             if (vsb.isVisible()) { w -= vsb.size().width; }
  1991.         }
  1992.  
  1993.         b.reshape(left, 0, w, headingHeight+2);
  1994.  
  1995.         return b;
  1996.     }
  1997.  
  1998.     /**
  1999.      * Gets the bounds of the row heading cell at the specified coordinate
  2000.      * @param cell The row heading cell
  2001.      * @param b The rectangle to place the bounds values
  2002.      */
  2003.     public Rectangle getRowHeadingBounds(TableCell cell, Rectangle b) {
  2004.         b = getCellBounds(cell.getCoordinates(), b);
  2005.         b.x = 0;
  2006.         b.width = rowHeadingWidth+1;
  2007.  
  2008.         return b;
  2009.     }
  2010.  
  2011.     /**
  2012.      * Redraws a particular cell only.<p>
  2013.      * This function should only be called if selection has not changed since last
  2014.      * redraw.  This function is provided to more efficiently redraw individual
  2015.      * cell updates
  2016.      */
  2017.     public void redrawCell(TableCell c) {
  2018.         redrawCell(c, true);
  2019.     }
  2020.  
  2021.     /**
  2022.      * Redraws a particular cell only.<p>
  2023.      * This function should only be called if selection has not changed since last
  2024.      * redraw.  This function is provided to more efficiently redraw individual
  2025.      * cell updates
  2026.      * @param c The cell to redraw
  2027.      * @param makeVisible Specifies whether the cell should be scrolled
  2028.      *      to make visible before being drawn
  2029.      */
  2030.     public /* synchronized */ void redrawCell(TableCell c, boolean makeVisible) {
  2031.         try {
  2032.             if (!fetchMode) { dataSource.fetchMode(true); }
  2033.  
  2034.             if (c != cornerCell && c.type() != TableCell.COL_HEADING
  2035.                 && makeVisible && isCellVisible(c.row()+1, c.col()+1))
  2036.             {
  2037.                 //make sure cell is visible if not heading
  2038.                 makeCellVisible(c.row()+1, c.col()+1);
  2039.             } else if (!isCellVisible(c.row()+1, c.col()+1)) {
  2040.                 return;
  2041.             }
  2042.  
  2043.             hints.setHints(c);
  2044.  
  2045.             //clear rectangle
  2046.             gg.setColor(getBackground());
  2047.             Rectangle r = hints.bounds();
  2048.             gg.fillRect(r.x, r.y, r.width-1, r.height-1);
  2049.             gg.setColor(getForeground());
  2050.  
  2051.             c.drawCell(gg, hints);
  2052.             if (c == currSelectedCell && c.isCellTypeEditable()) {
  2053.                 frameCurrentCells();
  2054.             }
  2055.         } finally {
  2056.             if (!fetchMode) { dataSource.fetchMode(false); }
  2057.         }
  2058.  
  2059.         repaint();
  2060.     }
  2061.  
  2062.  
  2063.     /**
  2064.      * Redraws a particular cell only.<p>
  2065.      * This function should only be called if selection has not changed since last
  2066.      * redraw.  This function is provided to more efficiently redraw individual
  2067.      * cell updates.  This function is internal so it is 0 relative.
  2068.      * @param row The row of the cell to redraw
  2069.      * @param col The column of the cell to redraw
  2070.      * @param makeVisible Specifies whether the cell should be scrolled
  2071.      *      to make visible before being drawn
  2072.      */
  2073.     protected /* synchronized */ void redrawCell(int row, int col, boolean makeVisible) {
  2074.         if (!validRow(row)) {
  2075.             //not asking to redraw a column heading
  2076.             return;
  2077.         } else if (col > -1 && !validCol(col)) {
  2078.             //not asking to redraw a row heading
  2079.             return;
  2080.         } else if (col == -1 && validRow(row)) {
  2081.             redrawRowHeadingCell(row);
  2082.             return;
  2083.         } else if (col == -1 && row == -1) {
  2084.             //corner cell and we are not worried about it
  2085.             return;
  2086.         }
  2087.  
  2088.         TableCell c = getUniqueCell(row, col);
  2089.         redrawCell(c, makeVisible);
  2090.         drawTableBoundary();
  2091.     }
  2092.  
  2093.     /**
  2094.      * Redraws all the cells in a row.
  2095.      */
  2096.     public /* synchronized */ void redrawRow(int row) {
  2097.         row--;
  2098.         if(!validRow(row)) {
  2099.             return;
  2100.         }
  2101.  
  2102.         fetchMode = true;
  2103.         dataSource.fetchMode(true);
  2104.         try {
  2105.             int cols = getNumberOfCols();
  2106.             for (int col=0; col<cols; col++) {
  2107.                 redrawCell(row, col, false);
  2108.             }
  2109.  
  2110.             redrawRowHeadingCell(row);
  2111.         } finally {
  2112.             dataSource.fetchMode(false);
  2113.             fetchMode = false;
  2114.         }
  2115.  
  2116.         if (autoRedraw) { redrawAsync(); }
  2117.     }
  2118.  
  2119.     /**
  2120.      * Redraws the specified cell and all of the bordering cells
  2121.      */
  2122.     public /* synchronized */ void redrawAroundCell(TableCell c) {
  2123.         //draw on all adjoining cells too
  2124.         int row = c.row()-1;
  2125.         int col = c.col()-1;
  2126.         try {
  2127.             fetchMode = true;
  2128.             dataSource.fetchMode(true);
  2129.  
  2130.             for (int i=0; i<=2; i++) {
  2131.                 for (int j=0; j<=2; j++) {
  2132.                     if (col+j > getNumberOfCols()-1) {
  2133.                         continue;
  2134.                     }
  2135.  
  2136.                     //redraw col heading
  2137.                     if (row+i < topRow) {
  2138.                         if (col+j < leftCol-1) {
  2139.                             //redraw corner cell
  2140.                             redrawCornerCell();
  2141.                         }
  2142.  
  2143.                         redrawColHeadingCell(col+j);
  2144.                     } else {
  2145.                         //redraw regular cell
  2146.                         if (isCellVisible(row+i+1, col+j+1)) {
  2147.                             redrawCell(row + i, col + j, false);
  2148.                         }
  2149.                     }
  2150.                 }
  2151.             }
  2152.         } finally {
  2153.             fetchMode = false;
  2154.             dataSource.fetchMode(false);
  2155.         }
  2156.     }
  2157.  
  2158.     /**
  2159.      * Gets the visible bounds of the drawing space required for the cells in
  2160.      * the Grid.
  2161.      */
  2162.     public Rectangle getTableBounds(Rectangle r) {
  2163.         Dimension d = size();
  2164.         r.reshape(0, 0, d.width, d.height);
  2165.  
  2166.         if (vsb.isVisible()) {
  2167.             r.width -= vsb.size().width;
  2168.         }
  2169.         r.height -= bottomPanel.size().height;
  2170.         r.width = splitters[splitters.length-1] - splitters[leftCol-1] + 1;
  2171.         if (rowHeadingHints.visible) {
  2172.             r.width += rowHeadingWidth;
  2173.         }
  2174.  
  2175.         int visRows = (r.height-2)/cellHeight;
  2176.         if (visRows + topRow > dataSource.rows()) {
  2177.             r.height = headingHeight+2 + cellHeight*(dataSource.rows() - topRow)+2;
  2178.         }
  2179.  
  2180.         return r;
  2181.     }
  2182.  
  2183.     /**
  2184.      * Draws the outline around the cells
  2185.      */
  2186.     protected void drawTableBoundary() {
  2187.         Dimension d = size();
  2188.         Rectangle r = new Rectangle(0, 0, d.width, d.height);
  2189.  
  2190.         //draw boundary around table panel
  2191.         if (vsb.isVisible()) {
  2192.             r.width -= vsb.size().width;
  2193.         }
  2194.         r.height -= bottomPanel.size().height;
  2195.  
  2196.         gg.setColor(Color.black);
  2197.         gg.drawRect(r.x, r.y, r.width-1, r.height-1);
  2198.  
  2199.         //draw boundary around table
  2200.         r.width = splitters[splitters.length-1] - splitters[leftCol-1] + 1;
  2201.         if (rowHeadingHints.visible) {
  2202.             r.width += rowHeadingWidth;
  2203.         }
  2204.  
  2205.         int visRows = (r.height-2)/cellHeight;
  2206.         if (visRows + topRow > dataSource.rows()) {
  2207.             r.height = headingHeight+2 + cellHeight*(dataSource.rows() - topRow)+2;
  2208.         }
  2209.  
  2210.         gg.drawRect(r.x, r.y, r.width-1, r.height-1);
  2211.     }
  2212.  
  2213.     /**
  2214.      * Gets the bounds for the visible cells.
  2215.      */
  2216.     protected Rectangle getVisibleCellBoundary() {
  2217.         Dimension d = size();
  2218.         Rectangle r = new Rectangle(0, 0, d.width, d.height);
  2219.  
  2220.         //get height of table panel
  2221.         r.height -= bottomPanel.size().height;
  2222.  
  2223.         //get boundary around table
  2224.         r.width = splitters[splitters.length-1] - splitters[leftCol-1] + 1;
  2225.         if (rowHeadingHints.visible) {
  2226.             r.width += rowHeadingWidth;
  2227.         }
  2228.  
  2229.         int visRows = (r.height-2)/cellHeight;
  2230.         if (visRows + topRow > dataSource.rows()) {
  2231.             r.height = headingHeight+2 + cellHeight*(dataSource.rows() - topRow)+2;
  2232.         }
  2233.  
  2234.         return r;
  2235.     }
  2236.  
  2237.     /**
  2238.      * Inserts a new row above the specified row number
  2239.      * @exception   TypeNotSupported If action is not supported by the DataSource
  2240.      */
  2241.     public /* synchronized */ void insertRow(int beforeRow) throws TypeNotSupported {
  2242.         Event e = new Event(this, INSERT, null);
  2243.         beforeRow--;
  2244.         e.y = beforeRow;
  2245.         if (!dataSource.handleEvent(e)) {
  2246.             dataSource.insertRow(beforeRow);
  2247.         }
  2248.  
  2249.         /*
  2250.         if (currSelectedCell != null &&
  2251.             currSelectedCell.row() >= beforeRow)
  2252.         {
  2253.             currSelectedCell.setRow(currSelectedCell.row()+1);
  2254.         }
  2255.  
  2256.         if (autoRedraw) { redrawAsync(); }
  2257.         */
  2258.     }
  2259.  
  2260.     /**
  2261.      * Gets the state of the data in the specified row
  2262.      * @return One of NEW_ROW, CLEAN_ROW, DELETED_ROW, MODIFIED_ROW as defined in
  2263.      *      DataSource
  2264.      */
  2265.     public int rowState(int row) {
  2266.         row--;
  2267.         return dataSource.rowState(row);
  2268.     }
  2269.  
  2270.     /**
  2271.      * Mark the specified row as not deleted
  2272.      * @exception   TypeNotSupported If action is not supported by the DataSource
  2273.      */
  2274.     public void undeleteRow(int row) throws TypeNotSupported {
  2275.  
  2276.         undoCurrentCell();  // Just to make sure we can redraw it
  2277.         setFocusToRow(row);
  2278.         row--;
  2279.  
  2280.         Event e = new Event(this, UNDELETE, null);
  2281.         e.y = row;
  2282.         if (!dataSource.handleEvent(e)) {
  2283.             dataSource.undeleteRow(row);
  2284.             row++;
  2285.             //setFocusToRow(row);
  2286.         }
  2287.     }
  2288.  
  2289.     /**
  2290.      * Mark the specified row as deleted
  2291.      * @exception   TypeNotSupported If action is not supported by the DataSource
  2292.      */
  2293.     public void deleteRow(int row) throws TypeNotSupported {
  2294.         undoCurrentCell();  // Just to make sure we can redraw it
  2295.         setFocusToRow(row);
  2296.         row--;
  2297.         Event e = new Event(this, DELETE, null);
  2298.         e.y = row;
  2299.         if (!dataSource.handleEvent(e)) {
  2300.             dataSource.deleteRow(row);
  2301.  
  2302.  
  2303.         }
  2304.  
  2305.         row++;
  2306.  
  2307.         // Trial 0
  2308.          //clearCurrentCell();
  2309.         // setFocusToRow(row);
  2310.  
  2311.         // Trial 1
  2312.         //setFocusToRow(row);
  2313.  
  2314.         // Trial 2
  2315.         // redrawRow(row);
  2316.         // sendFocusEvents(null, currSelectedCell);
  2317.  
  2318.         // Trial 3
  2319.          //redrawRowHeadingCell(row);
  2320.         //repaint();
  2321.  
  2322.  
  2323.         // if (autoRedraw) { redrawAsync(); }
  2324.     }
  2325.  
  2326.     /**
  2327.      * Appends a new row to the end of the Grid
  2328.      * @exception   TypeNotSupported If action is not supported by the DataSource
  2329.      */
  2330.     public int appendRow() throws TypeNotSupported {
  2331.         Event   e = new Event(this, APPEND, null);
  2332.         int     newRow;
  2333.  
  2334.         if (!dataSource.handleEvent(e)) {
  2335.             newRow = dataSource.appendRow();
  2336.         } else {
  2337.             newRow = e.y;
  2338.         }
  2339.  
  2340.         if (autoRedraw) { redrawAsync(); }
  2341.         return newRow;
  2342.     }
  2343.  
  2344.     /**
  2345.      * Creates a new cell and adds it to the Matrix used to store TableCells.
  2346.      * @param cell The default cell to clone to make the new cell.
  2347.      */
  2348.     public void addCellFromDefault(TableCell cell) {
  2349.         TableCell c = cell.cloneCell();
  2350.         cells.addElement(c.row(), c.col(), c);
  2351.         if (currSelectedCell == cell) { currSelectedCell = c; }
  2352.         if (currCaptureCell == cell) { currCaptureCell = c; }
  2353.     }
  2354.  
  2355.     /**
  2356.      * Gets the default cell and sets the coordinates to the specified values
  2357.      */
  2358.     protected TableCell getDefaultCell(int row, int col) {
  2359.         TableCell cell = defaultCell;
  2360.         Coordinate c = cell.getCoordinates();
  2361.         cell.reset();
  2362.         c.row = row;
  2363.         c.col = col;
  2364.  
  2365.         return cell;
  2366.     }
  2367.  
  2368.     /**
  2369.      * Gets the cell at the specified coordinats.  If the cell does not exist in
  2370.      * the cells Matrix, then the default cell is returned.
  2371.      */
  2372.     protected TableCell getCell(int row, int col) {
  2373.         if (currSelectedCell != null
  2374.             && currSelectedCell.row() == row && currSelectedCell.col() == col)
  2375.         {
  2376.             return currSelectedCell;
  2377.         } else if (cells.contains(row, col)) {
  2378.             return (TableCell)cells.elementAt(row, col);
  2379.         } else {
  2380.             return getDefaultCell(row, col);
  2381.         }
  2382.     }
  2383.  
  2384.     /**
  2385.      * Requests the DataSource to save the current state of the Grid
  2386.      * @exception   TypeNotSupported If action is not supported by the DataSource
  2387.      */
  2388.     public void save() throws TypeNotSupported {
  2389.         dataSource.commitData();
  2390.         dataSource.save();
  2391.         redrawAsync();
  2392.         /*
  2393.         if (currSelectedCell != null) {
  2394.             try {
  2395.                 dataSource.validDataRowRange(currSelectedCell.row(),
  2396.                                              currSelectedCell.row());
  2397.             } catch(DataNotAvailable ex) {
  2398.                 currSelectedCell = null;
  2399.                 currCaptureCell = null;
  2400.                 return;
  2401.             }
  2402.  
  2403.             dataSource.setCurrentRow(currSelectedCell.row());
  2404.         }
  2405.         */
  2406.     }
  2407.  
  2408.     /**
  2409.      * Requests the DataSource to refresh its data.  Same as refresh but for
  2410.      * backward compatibility.
  2411.      */
  2412.     public void restart() {
  2413.         refresh();
  2414.     }
  2415.  
  2416.     /**
  2417.      * Requests the DataSource to refresh its data.
  2418.      */
  2419.     public void refresh() {
  2420.         dataSource.refresh();
  2421.         /*
  2422.         currSelectedCell = null;
  2423.         currCaptureCell = null;
  2424.         redrawAsync();
  2425.         */
  2426.     }
  2427.  
  2428.     /**
  2429.      * Redraws the grid's offscreen image.  Call when through making changes to grid.
  2430.      * @param repaint If true, grid will be repainte after it is redrawn
  2431.      *      offscreen.
  2432.      */
  2433.     public void redraw(boolean repaint) {
  2434.         redraw();
  2435.         if (repaint) {
  2436.             repaint();
  2437.         }
  2438.     }
  2439.  
  2440.     /**
  2441.      * Redraws the Grid.  Call when through making changes to Grid. Does not
  2442.      *      force a redraw of the offscreen image.
  2443.      */
  2444.     public void redraw() {
  2445.         Dimension d = size();
  2446.  
  2447.         if (width != d.width || height != d.height)  {
  2448.             im = createImage(width = d.width,
  2449.                              height = d.height);
  2450.             if (im == null) return;
  2451.             gg = im.getGraphics();
  2452.         }
  2453.  
  2454.         forceRedraw(false);
  2455.     }
  2456.  
  2457.     /**
  2458.      * Forces the offscreen image to be redraw.  It does not check for a size
  2459.      * change since the last redraw.
  2460.      */
  2461.     public void forceRedraw(boolean repaint) {
  2462.         // /* synchronized */(dataSource.getSynchronizationObject())
  2463.         {
  2464.             // System.out.println("**** Drawing rows for " + name);
  2465.             if (gg == null)
  2466.             {
  2467.                 // System.out.println("Nothing to draw for " + name);
  2468.                 return;
  2469.             }
  2470.             gg.setColor(getBackground());
  2471.             gg.fillRect(0,0,width,height);
  2472.             int count = 0;
  2473.             try {
  2474.                 fetchMode = true;
  2475.                 dataSource.fetchMode(true);
  2476.                 setTopRow();
  2477.                 showScrollbars();
  2478.                 count = getNumberOfVisibleRows();
  2479.                 drawHeadings(count);
  2480.                 drawRows(count, topRow);
  2481.                 drawTableBoundary();
  2482.             } finally {
  2483.                 fetchMode = false;
  2484.                 dataSource.fetchMode(false);
  2485.             }
  2486.             // System.out.println("@@@ Done drawing rows for " + name);
  2487.  
  2488.             if (repaint) repaint();
  2489.         }
  2490.     }
  2491.  
  2492. public String name;
  2493.  
  2494.     void drawRows(int count, int cellRow) {
  2495.         int                 r = 0;
  2496.         MatrixEnumeration   e = cells.elements();
  2497.         TableCell           c = null;
  2498.         int                 x, w;
  2499.         int                 cols = getNumberOfCols();
  2500.         int                 hx=0, hy=0, hw=0, hh=0;
  2501.         int                 shiftLeft = splitters[leftCol-1];
  2502.         int                 currRow=-1, currCol=-1;
  2503.  
  2504.         if (cellRow > 0) {
  2505.             if (cellRow >= cells.rows()) {
  2506.                 e = null;
  2507.             } else {
  2508.                 c  = (TableCell)e.advanceTo(cellRow);
  2509.             }
  2510.         }
  2511.         int lastVisCol = lastVisibleCol();
  2512.         //iterate the rows and paint each one
  2513.         while(count-- > 0) {
  2514.             //iterate the cols of the current row
  2515.             for (int col=leftCol-1; col<cols && col<=lastVisCol; col++) {
  2516.                 w = getColumnWidth(col);
  2517.                 while (e != null
  2518.                        && (c == null || (e.currCol() < col && e.currRow() <= cellRow))
  2519.                        && e.hasMoreElements())
  2520.                 {
  2521.                     c = (TableCell)e.nextElement();
  2522.                     currRow = e.currRow();
  2523.                     currCol = e.currCol();
  2524.                     if (currRow <= cellRow && currCol < col) {
  2525.                         //keep going till get to correct column
  2526.                         c = null;
  2527.                     }
  2528.                 }
  2529.  
  2530.                 if (currRow == cellRow && currCol == col) {
  2531.                     hints.setHints(c);
  2532.                     c.drawCell(gg, hints);
  2533.                     c = null;
  2534.                 } else
  2535.                 if (currSelectedCell != null &&
  2536.                     //it is default cell, but could be currSelectedCell
  2537.                         currSelectedCell.row() == cellRow &&
  2538.                         currSelectedCell.col() == col)
  2539.                 {
  2540.                     hints.setHints(currSelectedCell);
  2541.                     currSelectedCell.drawCell(gg, hints);
  2542.                 } else {
  2543.                     //looks like this cell not set yet so use default
  2544.                     TableCell defCell = getDefaultCell(cellRow, col);
  2545.                     hints.setHints(defCell);
  2546.                     defCell.drawCell(gg, hints);
  2547.  
  2548.                 }
  2549.  
  2550.             }
  2551.             cellRow++;
  2552.             r++;
  2553.         }
  2554.  
  2555.         if (currSelectedCell != null && currSelectedCell.isCellTypeEditable()) {
  2556.             frameCurrentCells();
  2557.         }
  2558.     }
  2559.  
  2560.     boolean drawFrame = true;
  2561.  
  2562.     /**
  2563.      * Sets whether current cell should have a frame drawn around it
  2564.      */
  2565.     public boolean drawFrame() { return drawFrame; }
  2566.  
  2567.     /**
  2568.      * Gets whether current cell should have a frame drawn around it
  2569.      */
  2570.     public boolean drawFrame(boolean draw) {
  2571.         drawFrame = draw;
  2572.  
  2573.         if (autoRedraw) {
  2574.             redrawAsync();
  2575.         }
  2576.  
  2577.         return draw;
  2578.     }
  2579.  
  2580.     void frameCurrentCells() {
  2581.         if (drawFrame && currSelectedCell != null) {
  2582.             Rectangle r = getCellBounds(currSelectedCell);
  2583.             if (r.x < rowHeadingWidth || r.y < headingHeight+2) { return; }
  2584.             gg.setColor(Color.black);
  2585.             gg.drawRect(r.x-1,r.y-1,r.width+1,r.height+1);  //draw outside
  2586.             gg.drawRect(r.x+1,r.y+1,r.width-3,r.height-3);  //draw inside
  2587.         }
  2588.     }
  2589.  
  2590.     int[] getColStartPositions() {
  2591.        return splitters;
  2592.     }
  2593.  
  2594.  
  2595.     /**
  2596.      * If the event handler is set, the exception is passed to the event handler.<p>
  2597.      * This function is 0 relative!!
  2598.      */
  2599.     public void handleException(int row, int col, Exception ex) {
  2600.         try {
  2601.             if (eventHandler != null) {
  2602.                 eventHandler.handleException(new Coordinate(row, col), ex);
  2603.             }
  2604.         }
  2605.         catch (Exception e)
  2606.         {
  2607.         }
  2608.  
  2609.     }
  2610.  
  2611.     /**
  2612.      * Requests the DataSource to undo some action to the specified row
  2613.      * @exception   TypeNotSupported If action is not supported by the DataSource
  2614.      */
  2615.     public void undoRow(int row) throws TypeNotSupported {
  2616.         undoCurrentCell();
  2617.         if (rowState(row) == DataSource.MODIFIED_ROW)
  2618.         {
  2619.             row--;
  2620.             dataSource.undoRow(row);
  2621.             row++;
  2622.             setFocusToRow(row);
  2623.         }
  2624.     }
  2625.  
  2626.     /**
  2627.      * Requests the DataSource to undo any changes made to the current cell
  2628.      * since the last commit.
  2629.      */
  2630.     public /* synchronized */ void undoCurrentCell() {
  2631.         dataSource.rollbackCurrentData();
  2632.         if (currSelectedCell != null) {
  2633.             redrawCell(currSelectedCell);
  2634.         }
  2635.     }
  2636.  
  2637.     /**
  2638.      * Generates a Grid event and routes it through the grid for handling.
  2639.      * It is forwarded to the DataSource and the event handler.  If not
  2640.      * handled by either, then it is forwarded through postEvent.
  2641.      * CAUTION - CAUTION - CAUTION - CAUTION - CAUTION - CAUTION - CAUTION
  2642.      *
  2643.      * This method should only be called with Grid events!!!!!
  2644.      *
  2645.      * NOITUAC - NOITUAC - NOITUAC - NOITUAC - NOITUAC - NOITUAC - NOITUAC
  2646.      */
  2647.     public /* synchronized */ boolean generateEvent(Event e, int id, TableCell cell) {
  2648.         //save old info so can restore
  2649.         Object  oldTarget = e.target;
  2650.         int     oldId = e.id;
  2651.         Object  oldArg = e.arg;
  2652.  
  2653.         boolean handled = false;
  2654.  
  2655.         //update the event
  2656.         e.id = id;
  2657.         e.target = this;
  2658.         e.arg = cell;
  2659.  
  2660.         //always let the event go to the DataSource
  2661.         handled = dispatchCellEvent(e);
  2662.  
  2663.         //send the event to the datasource, if not handled there then send it up
  2664.         if (!dataSource.handleEvent(e)) {
  2665.             handled |= postEvent(e);
  2666.         }
  2667.  
  2668.         //restore event object
  2669.         e.target = oldTarget;
  2670.         e.id = oldId;
  2671.         e.arg = oldArg;
  2672.  
  2673.         return handled;
  2674.     }
  2675.  
  2676.     boolean dispatchCellEvent(Event e) {
  2677.         if (eventHandler != null && e.arg instanceof TableCell) {
  2678.             TableCell cell = (TableCell)e.arg;
  2679.  
  2680.         if (rowHeadingCell(cell)) {
  2681.  
  2682.                 return eventHandler.handleRowHeadingEvent(e, cell);
  2683.             } else if (cell.type() == TableCell.COL_HEADING) {
  2684.                 return eventHandler.handleColHeadingEvent(e, cell);
  2685.             } else if (cell == cornerCell) {
  2686.                 return eventHandler.handleCornerCellEvent(e, cell);
  2687.             } else {
  2688.                 //must be a cell
  2689.                 return eventHandler.handleCellEvent(e, cell);
  2690.             }
  2691.         }
  2692.  
  2693.         return false;
  2694.     }
  2695.  
  2696.     boolean handleHeadingClick(Event e, int x, int y) {
  2697.         int colstart[] = getColStartPositions();
  2698.         int shiftLeft = colstart[leftCol-1] - rowHeadingWidth;
  2699.  
  2700.         if (x <= rowHeadingWidth && rowHeadingHints.visible) {
  2701.             //it was a click in row header region
  2702.                 if ((x < rowHeadingWidth + clickMargin) &&
  2703.                     (x > rowHeadingWidth - clickMargin))   {
  2704.                     dragColumn = 0;
  2705.                     isDragging = true;
  2706.                     mouseDrag(e, x, y); //draw drag line immediately
  2707.                 } else {
  2708.                     //upper left corner clicked
  2709.                     if (rowHeadingCell(currCaptureCell)) {
  2710.                         currHeadingCell = null;
  2711.                     }
  2712.  
  2713.                     currCaptureCell = cornerCell;
  2714.                     translate(e);
  2715.                     return cornerCell.mouseEvent(e);
  2716.                 }
  2717.             return true;
  2718.         } else {
  2719.             // is it close enough to be a column size drag?
  2720.             for (int i=leftCol-1; i<splitters.length; i++) {
  2721.                 if ((x < colstart[i] + clickMargin - shiftLeft) &&
  2722.                     (x > colstart[i] - clickMargin - shiftLeft))   {
  2723.                     dragColumn = i;
  2724.                     isDragging = true;
  2725.                     mouseDrag(e, x, y); //draw drag line immediately
  2726.                     return true;
  2727.                 }
  2728.             }
  2729.         }
  2730.  
  2731.         //get the heading for the coordinates
  2732.         TableCell cell = (TableCell)colHeadings.elementAt(0, columnClicked(x));
  2733.  
  2734.         if (cell == null) {
  2735.             return true;
  2736.         }
  2737.  
  2738.         if (rowHeadingCell(currCaptureCell)) {
  2739.             currHeadingCell = null;
  2740.         }
  2741.  
  2742.         currCaptureCell = cell;
  2743.         translate(e);
  2744.         return cell.mouseEvent(e);
  2745.     }
  2746.  
  2747.     boolean handleRowHeadingClick(Event e, int x, int y) {
  2748.         //return true;
  2749.  
  2750.         //create a new current heading cell since this could be a shared resource
  2751.         //during event handling
  2752.         //get the heading for the coordinates
  2753.         currHeadingCell = headingCell.cloneCell();
  2754.         Coordinate c = currHeadingCell.getCoordinates();
  2755.         c.row = cellRow(y);
  2756.         c.col = 0;
  2757.  
  2758.         if (!validRow(c.row)) return true;
  2759.         currCaptureCell = currHeadingCell;
  2760.  
  2761.         translate(e);
  2762.        /* try{
  2763.  
  2764.  
  2765.                 dataSource.setCurrentRow(c.row);
  2766.  
  2767.         } catch(TypeNotSupported ex) { handleException(c.row, c.col, ex); }*/
  2768.  
  2769.         return currHeadingCell.mouseEvent(e);
  2770.  
  2771.     }
  2772.  
  2773.     boolean handleSuccessiveClick(Event e) {
  2774.         //must only be called if no focus change
  2775.         // track time elapsed since last mouseDown
  2776.         long clickSpeed = e.when - clickTime;
  2777.         TableCell cell = (currCaptureCell != null) ?currCaptureCell  :currSelectedCell;
  2778.         boolean handled;
  2779.  
  2780.         if (cell == null) {
  2781.             handled = false;
  2782.         } else if (clickSpeed < CLICKTHRESHOLD) {
  2783.             e.target = cell;
  2784.             e.id = CELL_MOUSE_DOUBLE;
  2785.             translate(e);
  2786.             handled = cell.mouseEvent(e);
  2787.         } else {
  2788.             //single click so send mouse event to control
  2789.             e.target = cell;
  2790.             translate(e);
  2791.             handled = cell.mouseEvent(e);
  2792.         }
  2793.  
  2794.         clickTime  = e.when;
  2795.         return handled;
  2796.     }
  2797.  
  2798.     int cellRow(int y) {
  2799.         return ((int)(y-headingHeight-2)/cellHeight)+topRow;
  2800.     }
  2801.  
  2802.     int columnClicked(int x) {
  2803.         int shiftLeft = splitters[leftCol - 1] - rowHeadingWidth;
  2804.  
  2805.         for (int i=0; i<getNumberOfCols()-1; i++) {
  2806.             if (x < splitters[i+1] - shiftLeft)   {
  2807.                 return i;
  2808.             }
  2809.         }
  2810.  
  2811.         if (x < rowHeadingWidth)
  2812.             return -1; //header click
  2813.         else
  2814.             return getNumberOfCols()-1;
  2815.     }
  2816.  
  2817.     void setFocusToRow(int row)
  2818.     {
  2819.         row--;
  2820.         if (currSelectedCell == null || currSelectedCell.row() != row)
  2821.         {
  2822.             row++;
  2823.             gotoRow(row);
  2824.         }
  2825.         else
  2826.         {
  2827.             row++;
  2828.             redrawRow(row);
  2829.             sendFocusEvents(null, currSelectedCell);
  2830.         }
  2831.     }
  2832.  
  2833.     void sendFocusEvents(TableCell lost, TableCell get) {
  2834.         Event e = new Event(lost, Event.LOST_FOCUS, null);
  2835.         int oldRow = -1;
  2836.  
  2837.         if (currSelectedCell != null) {
  2838.             oldRow = currSelectedCell.row();
  2839.         }
  2840.         if (lost != null) {
  2841.             if (!lost.canLoseFocus()) {
  2842.                 //not a legal state so do not change
  2843.                 return;
  2844.             }
  2845.  
  2846.             //set selected cell to get so frame not drawn around cell
  2847.             currSelectedCell = get;
  2848.             lost.focusEvent(e);
  2849.             lostCapture();
  2850.         }
  2851.  
  2852.         try{
  2853.             if (oldRow != get.row())
  2854.             {
  2855.                 dataSource.setCurrentRow(get.row());
  2856.             }
  2857.         } catch(TypeNotSupported ex) { handleException(get.row(), get.col(), ex); }
  2858.  
  2859.         currSelectedCell = get;
  2860.         e.target = get;
  2861.         e.id = e.GOT_FOCUS;
  2862.         get.focusEvent(e);
  2863.         drawRowHeadings(getNumberOfVisibleRows());
  2864.  
  2865.         //change currently selected row now
  2866.         makeCellVisible(get.row()+1, get.col()+1);
  2867.         clickTime = 0;
  2868.     }
  2869.  
  2870.     /**
  2871.      * Inherited from Component
  2872.      */
  2873.     public boolean mouseExit(Event e, int x, int y) {
  2874.         frame().setCursor(Frame.DEFAULT_CURSOR);
  2875.         return true;
  2876.     }
  2877.  
  2878.     /**
  2879.      * Inherited from Component
  2880.      */
  2881.     public /* synchronized */ boolean mouseDown(Event e, int x, int y) {
  2882.         buttonFocus();
  2883.         if (e.target == vsb || e.target == hsb) {
  2884.             //Netscape exposes mouseDown events for Scrollbars
  2885.             return false;
  2886.         }
  2887.  
  2888.         Rectangle r = new Rectangle();
  2889.         r = getTableBounds(r);
  2890.         if (!r.inside(x, y)) {
  2891.             return false;
  2892.         }
  2893.  
  2894.         // Check for a click on the heading area:
  2895.         if (y<headingHeight+1) {
  2896.             return handleHeadingClick(e, x, y);
  2897.         } if (x < rowHeadingWidth && rowHeadingHints.visible) {
  2898.             //click in row heading area
  2899.             return handleRowHeadingClick(e, x, y);
  2900.         }
  2901.  
  2902.         //it's a click in the row area
  2903.         //check for hit on the scrollbar
  2904.         if (x > width) return true;
  2905.  
  2906.         // set new row selection
  2907.         int row = cellRow(y);
  2908.         int col = columnClicked(x);
  2909.  
  2910.         TableCell newSelection = null;
  2911.         if (currSelectedCell == null || row != currSelectedCell.row() ||
  2912.             col != currSelectedCell.col())
  2913.         {
  2914.             if (!cells.contains(row, col)) {
  2915.                 //check for mouse below last row
  2916.                 if (!validRow(row)) {
  2917.                     return true;
  2918.                 }
  2919.                 //then we need to use the default cell
  2920.                 newSelection = getDefaultCell(row, col).cloneCell();
  2921.                 newSelection.setDefaultFlag();
  2922.             } else {
  2923.                 newSelection = (TableCell)cells.elementAt(row, col);
  2924.             }
  2925.  
  2926.             sendFocusEvents(currSelectedCell, newSelection);
  2927.             if (cellHasCapture()) {
  2928.                 translate(e);
  2929.                 return currCaptureCell.mouseEvent(e);
  2930.             }
  2931.         } else {
  2932.             //check for double click since didn't change cells
  2933.             handleSuccessiveClick(e);
  2934.         }
  2935.  
  2936.         if (e.modifiers == Event.META_MASK) {
  2937.             //right mouse click
  2938.         }
  2939.  
  2940.  
  2941.         return false;
  2942.     }
  2943.  
  2944.     /**
  2945.      * Determines whether the specified row exists in the Grid. <p>
  2946.      * This function is 0 based
  2947.      */
  2948.     public boolean validRow(int row) {
  2949.         if (row < 0) return false;
  2950.  
  2951.         if (cells.rows()-1 > row) {
  2952.             return true;
  2953.         }
  2954.  
  2955.         try {
  2956.             dataSource.validDataRowRange(row, row);
  2957.         } catch(DataNotAvailable exc) {
  2958.             //Yep, it was a click below cells
  2959.             return false;
  2960.         }
  2961.  
  2962.         return true;
  2963.     }
  2964.  
  2965.     /**
  2966.      * Determines whether the specified column exists in the Grid. <p>
  2967.      * This function is 0 based
  2968.      */
  2969.     public boolean validCol(int col) {
  2970.         return col >= 0 && col < getNumberOfCols();
  2971.     }
  2972.  
  2973.     /**
  2974.      * Inherited from Component
  2975.      */
  2976.     public boolean mouseDrag(Event e, int x, int y) {
  2977.         if (isDragging)  {
  2978.             handleColDrag(x);
  2979.             return true;
  2980.         }
  2981.  
  2982.         if (cellHasCapture()) {
  2983.             translate(e);
  2984.             return currCaptureCell.mouseEvent(e);
  2985.         }
  2986.  
  2987.         return false;
  2988.     }
  2989.  
  2990.     boolean captureByHeading() {
  2991.         if (currCaptureCell == null) { return false; }
  2992.  
  2993.         Coordinate c = currCaptureCell.getCoordinates();
  2994.  
  2995.         return colHeadings.contains(c.row, c.col, currCaptureCell)
  2996.                || cornerCell == currCaptureCell;
  2997.     }
  2998.  
  2999.     boolean captureByRowHeading() {
  3000.         if (currCaptureCell == null) { return false; }
  3001.  
  3002.         return rowHeadingCell(currCaptureCell) || cornerCell == currCaptureCell;
  3003.     }
  3004.  
  3005.     Event translate(Event e) {
  3006.         //get coords of current cell
  3007.         TableCell cell = (currCaptureCell != null) ?currCaptureCell  :currSelectedCell;
  3008.  
  3009.         int row = cell.getCoordinates().row;
  3010.         int col = cell.getCoordinates().col;
  3011.         int currY = (row - topRow) * cellHeight + headingHeight + 2;
  3012.         int currX = splitters[col] - splitters[leftCol - 1];
  3013.  
  3014.         //translate event's x and y to cell relative
  3015.         if (!captureByRowHeading()) {
  3016.             e.x -= (currX + rowHeadingWidth);
  3017.         }
  3018.         if (!captureByHeading()) {
  3019.             e.y -= currY;
  3020.         }
  3021.  
  3022.         return e;
  3023.     }
  3024.  
  3025.     void handleColDrag(int x) {
  3026.         //fix any drag that went off the left side
  3027.         int shiftLeft = splitters[leftCol-1] + rowHeadingWidth;
  3028.  
  3029.         if (dragColumn == 0) {
  3030.             //dragging to change size of header area
  3031.             rowHeadingWidth = Math.max(0, x);
  3032.         } else if (x < splitters[dragColumn-1] - shiftLeft) {
  3033.             x = splitters[dragColumn-1] - shiftLeft;
  3034.         }
  3035.  
  3036.         //erase prvious drag line and draw in new position
  3037.         gg.setColor(getBackground());
  3038.         gg.setXORMode(Color.black);
  3039.         gg.drawLine(xDragLast,0, xDragLast, size().height);
  3040.         gg.drawLine(x, 0, x, size().height);
  3041.         gg.setColor(Color.black);
  3042.         gg.setPaintMode();
  3043.  
  3044.         //save x position of drag line
  3045.         xDragLast = x;
  3046.         repaint();
  3047.     }
  3048.  
  3049.     /**
  3050.      * Resizes the specified column so that the right side of the column
  3051.      * is set to the requested pixel position.
  3052.      * @param col The column number
  3053.      * @param rightSide The pixel position of the right side of the column
  3054.      */
  3055.     public /* synchronized */ void resizeColumn(int col, int rightSide) {
  3056.         int diff = rightSide - splitters[col] + splitters[leftCol-1];
  3057.         int len = splitters.length;
  3058.         splitters[col] = rightSide + splitters[leftCol-1];
  3059.         splitters[col] = Math.max(0, splitters[col]);
  3060.         for(int i=col+1;i<len;i++) {
  3061.             splitters[i] += diff;
  3062.         }
  3063.  
  3064.         if (autoRedraw) {
  3065.             redrawAsync();
  3066.         }
  3067.  
  3068.     }
  3069.  
  3070.     /**
  3071.      * Inherited from Component
  3072.      */
  3073.     public /* synchronized */ boolean mouseUp(Event e, int x, int y) {
  3074.         if (isDragging) {
  3075.             //erase drag line
  3076.             gg.setColor(getBackground());
  3077.             gg.setXORMode(Color.black);
  3078.             gg.drawLine(xDragLast, 0, xDragLast, size().height);
  3079.             gg.setColor(Color.black);
  3080.             gg.setPaintMode();
  3081.  
  3082.             //set column width to dragged position
  3083.             if (dragColumn == 0) {
  3084.                 //changed header size
  3085.                 redrawAsync();
  3086.             } else {
  3087.                 resizeColumn(dragColumn, xDragLast - rowHeadingWidth);
  3088.             }
  3089.  
  3090.             //turn off dragging
  3091.             xDragLast = -1;
  3092.             isDragging = false;
  3093.  
  3094.             return true;
  3095.         } else {
  3096.             if (cellHasCapture()) {
  3097.                 translate(e);
  3098.                 return currCaptureCell.mouseEvent(e);
  3099.             }
  3100.         }
  3101.         return false;
  3102.     }
  3103.  
  3104.     /**
  3105.      * Inherited from Component
  3106.      */
  3107.     public /* synchronized */ boolean mouseMove(Event ev, int x, int y) {
  3108.         boolean     isCloseEnough = false;
  3109.         int         shiftLeft = splitters[leftCol-1] - rowHeadingWidth;
  3110.  
  3111.         if (y < headingHeight && locate(x, y) instanceof Scrollbar && vsb.isVisible()) {
  3112.             //noop - over vertical scrollbar but still might want to change cursor so
  3113.             //don't return yet.
  3114.         } else
  3115.         // Use resize cursor ?
  3116.         if (rowHeadingHints.visible && x<rowHeadingWidth+clickMargin && y < headingHeight) {
  3117.             if ((x < rowHeadingWidth + clickMargin) &&
  3118.                 (x > rowHeadingWidth - clickMargin))
  3119.             {
  3120.                 isCloseEnough = true;
  3121.             }
  3122.         } else if (y<headingHeight) {
  3123.                // Moving mouse around in header area
  3124.             // is it close enough to be a column size drag?
  3125.             for (int i=1; i<splitters.length; i++) {
  3126.                 if ((x < splitters[i] + clickMargin - shiftLeft) &&
  3127.                     (x > splitters[i] - clickMargin - shiftLeft))
  3128.                 {
  3129.                     isCloseEnough = true;
  3130.                 }
  3131.             }
  3132.         }
  3133.  
  3134.         currentCursor = (isCloseEnough? Frame.W_RESIZE_CURSOR : Frame.DEFAULT_CURSOR);
  3135.         if (currentCursor != frame().getCursorType()) {
  3136.             frame().setCursor(currentCursor );
  3137.         }
  3138.  
  3139.  
  3140.         return false;
  3141.     }
  3142.  
  3143.     /**
  3144.      * Inherited from Component
  3145.      */
  3146.     public /* synchronized */ boolean keyUp(Event e, int key) {
  3147.         int row, col;
  3148.         if (currSelectedCell == null) {
  3149.             row = topRow;
  3150.             col = 0;
  3151.         } else {
  3152.             row = currSelectedCell.row();
  3153.             col = currSelectedCell.col();
  3154.         }
  3155.  
  3156.         if (currSelectedCell != null) {
  3157.             e.target = currSelectedCell;
  3158.             return currSelectedCell.keyEvent(e);
  3159.         }
  3160.  
  3161.         return false;
  3162.     }
  3163.  
  3164.     /**
  3165.      * Inherited from Component
  3166.      */
  3167.     public /* synchronized */ boolean lostFocus(Event e, Object o) {
  3168.         if (tabbed) {
  3169.             requestFocus();
  3170.             buttonFocus();
  3171.             tabbed = false;
  3172.         } else {
  3173.             //need to deactivate cursor in current cell
  3174.              if (currSelectedCell != null) {
  3175.                 e.target = currSelectedCell;
  3176.                 e.target = this;
  3177.                 currSelectedCell.deactivateCursor();
  3178.             }
  3179.             lostCapture();
  3180.         }
  3181.  
  3182.         return false;
  3183.     }
  3184.  
  3185.     /**
  3186.      * Inherited from Component
  3187.      */
  3188.     public /* synchronized */ boolean gotFocus(Event e, Object o) {
  3189.         //need to activate the cursor in the current cell
  3190.          if (currSelectedCell != null) {
  3191.              currSelectedCell.activateCursor();
  3192.          }
  3193.  
  3194.         buttonFocus();
  3195.  
  3196.         return false;
  3197.     }
  3198.  
  3199.     private void buttonFocus() {
  3200.         if (onSolaris) {
  3201.               button.requestFocus();
  3202.           }
  3203.     }
  3204.  
  3205.     private void shapeButton() {
  3206.         if (onSolaris) {
  3207.               button.reshape(0, 0, 1, 1);
  3208.           }
  3209.     }
  3210.  
  3211.     TableCell getUniqueCell(int row, int col) {
  3212.         if (!cells.contains(row, col)) {
  3213.             //then we need to use the default cell
  3214.             TableCell cell = getDefaultCell(row, col).cloneCell();
  3215.             cell.setDefaultFlag();
  3216.             return cell;
  3217.         }
  3218.  
  3219.         return (TableCell)cells.elementAt(row, col);
  3220.     }
  3221.  
  3222.  
  3223.     /**
  3224.      * Inherited from Component
  3225.      */
  3226.     public /* synchronized */ boolean keyDown(Event e, int key) {
  3227.         TableCell   savedCell = currSelectedCell;
  3228.         if (savedCell != null)
  3229.         {
  3230.             // System.out.println("at the start: "  + String.valueOf(savedCell.col()));
  3231.         }
  3232.         boolean  success = true;
  3233.         boolean  changed = false;
  3234.         int row, col;
  3235.  
  3236.         if (eventHandler != null && isToolbarComponent(e.target)) {
  3237.             return eventHandler.handleToolbarEvent(e);
  3238.         }
  3239.  
  3240.         if (currSelectedCell == null) {
  3241.             row = topRow;
  3242.             col = 0;
  3243.         } else {
  3244.             row = currSelectedCell.row();
  3245.             col = currSelectedCell.col();
  3246.         }
  3247.  
  3248.         int dataRows = -1;
  3249.         try {
  3250.             dataRows = dataSource.validDataRowRange(0, row+2);
  3251.         } catch(DataNotAvailable exc) {}
  3252.         switch (key) {
  3253.             case '\n':
  3254.                 if (e.shiftDown()) {
  3255.                     if (currSelectedCell == null) { return false; }
  3256.                     if (!currSelectedCell.loseFocusOnArrow()) {
  3257.                         e.target = currSelectedCell;
  3258.                         return currSelectedCell.keyEvent(e);
  3259.                     }
  3260.  
  3261.                     if (row > 0) {
  3262.                            TableCell newSelection = getUniqueCell(row-1, col);
  3263.                         sendFocusEvents(currSelectedCell, newSelection);
  3264.                     }
  3265.                     break;
  3266.                 }
  3267.                 
  3268.             if (row < getNumberOfRows()-1) {
  3269.                     requestFocus();
  3270.                     TableCell newSelection = getUniqueCell(row+1, col);
  3271.                     sendFocusEvents(currSelectedCell, newSelection);
  3272.                     break;
  3273.                 }
  3274.             if (row == getNumberOfRows()-1) {
  3275.                     requestFocus();
  3276.                     TableCell newSelection = getUniqueCell(row, col);
  3277.                     sendFocusEvents(currSelectedCell, newSelection);
  3278.                     break;
  3279.                 }
  3280.                 break;
  3281.             case Event.DOWN:
  3282.                 if (currSelectedCell == null) { return false; }
  3283.                 if (!currSelectedCell.loseFocusOnArrow()) {
  3284.                     e.target = currSelectedCell;
  3285.                     return currSelectedCell.keyEvent(e);
  3286.                 }
  3287.  
  3288.                 if (row < cells.rows()-1 || row < dataRows) {
  3289.                        TableCell newSelection = getUniqueCell(row+1, col);
  3290.                     sendFocusEvents(currSelectedCell, newSelection);
  3291.                 }
  3292.                 break;
  3293.             case '\t':
  3294.                 // tabbed = true;
  3295.                 //if only tab is pressed
  3296.                 if (e.shiftDown()) {
  3297.                     if (col > 0) {
  3298.                         requestFocus();
  3299.                            TableCell newSelection = getUniqueCell(row, col-1);
  3300.                         sendFocusEvents(currSelectedCell, newSelection);
  3301.                     }
  3302.                     buttonFocus();
  3303.                     break;
  3304.                 }
  3305.  
  3306.                 //if only tab pressed then go right
  3307.                 if (col < getNumberOfCols()-1) {
  3308.                     requestFocus();
  3309.                        TableCell newSelection = getUniqueCell(row, col+1);
  3310.                     sendFocusEvents(currSelectedCell, newSelection);
  3311.                 }
  3312.                 break;
  3313.             case Event.RIGHT:
  3314.                 if (currSelectedCell == null) { return false; }
  3315.                 if (!currSelectedCell.loseFocusOnArrow()) {
  3316.                     e.target = currSelectedCell;
  3317.                     return currSelectedCell.keyEvent(e);
  3318.                 }
  3319.  
  3320.                 if (col < getNumberOfCols()-1) {
  3321.                     if (savedCell != null)
  3322.                     {
  3323.                         savedCell.setCol(savedCell.col() + 1);
  3324.                         // System.out.println("right: "  + String.valueOf(savedCell.col()));
  3325.                     }
  3326.                        TableCell newSelection = getUniqueCell(row, col+1);
  3327.                     sendFocusEvents(currSelectedCell, newSelection);
  3328.                 }
  3329.                 break;
  3330.             case Event.LEFT:
  3331.                 if (currSelectedCell == null) { return false; }
  3332.                 if (!currSelectedCell.loseFocusOnArrow()) {
  3333.                     e.target = currSelectedCell;
  3334.                     return currSelectedCell.keyEvent(e);
  3335.                 }
  3336.  
  3337.                 if (col > 0) {
  3338.                     if (savedCell != null)
  3339.                     {
  3340.                         savedCell.setCol(savedCell.col() - 1);
  3341.                         // System.out.println("left: "  + String.valueOf(savedCell.col()));
  3342.                     }
  3343.                        TableCell newSelection = getUniqueCell(row, col-1);
  3344.                     sendFocusEvents(currSelectedCell, newSelection);
  3345.                 }
  3346.                 break;
  3347.             case Event.UP:
  3348.                 if (currSelectedCell == null) { return false; }
  3349.                 if (!currSelectedCell.loseFocusOnArrow()) {
  3350.                     e.target = currSelectedCell;
  3351.                     return currSelectedCell.keyEvent(e);
  3352.                 }
  3353.  
  3354.                 if (row > 0) {
  3355.                        TableCell newSelection = getUniqueCell(row-1, col);
  3356.                     sendFocusEvents(currSelectedCell, newSelection);
  3357.                 }
  3358.                 break;
  3359.             case Event.PGDN:
  3360.                 scrollPageDown();
  3361.                 changed = true;
  3362.                 break;
  3363.             case Event.PGUP:
  3364.                 scrollPageUp();
  3365.                 changed = true;
  3366.                 break;
  3367.             case Event.END:
  3368.                 if (currSelectedCell == null || currSelectedCell.loseFocusOnArrow()) {
  3369.                     if (e.controlDown()) {
  3370.                         setCurrentCell(getNumberOfRows(),
  3371.                                        getNumberOfCols());
  3372.                     } else {
  3373.                         //this call is one relative
  3374.                         setCurrentCell(currSelectedCell.row() + 1,
  3375.                                             getNumberOfCols());
  3376.                     }
  3377.                     return true;
  3378.                 }
  3379.             case Event.HOME:
  3380.                 if (currSelectedCell == null || currSelectedCell.loseFocusOnArrow()) {
  3381.                     if (e.controlDown()) {
  3382.                         //this call is one relative
  3383.                         setCurrentCell(1, 1);
  3384.                         return true;
  3385.                     } else {
  3386.                         //this call is one relative
  3387.                         setCurrentCell(currSelectedCell.row() + 1, 1);
  3388.                         return true;
  3389.                     }
  3390.                 }
  3391.             default:
  3392.                 if (currSelectedCell != null) {
  3393.                     e.target = currSelectedCell;
  3394.                     return currSelectedCell.keyEvent(e);
  3395.                 }
  3396.  
  3397.         }
  3398.  
  3399.         if (changed) redrawAsync();
  3400.  
  3401.         return success;
  3402.     }
  3403.  
  3404.     boolean redrawAgain = false;
  3405.     Integer redrawAgainCount = new Integer(0);
  3406.  
  3407.     void setRedrawAgain(boolean value)
  3408.     {
  3409.         // System.out.println(Thread.currentThread().getName()
  3410.         //     + " : " + name + " : Entering set...");
  3411.         // /* synchronized */(redrawAgainCount)
  3412.         {
  3413.             // System.out.println(Thread.currentThread().getName()
  3414.             //     + " : " + name + " : Inside set...");
  3415.             redrawAgain = value;
  3416.         }
  3417.         // System.out.println(Thread.currentThread().getName()
  3418.         //     + " : " + name + " : Leaving set...");
  3419.     }
  3420.  
  3421.     boolean getRedrawAgain()
  3422.     {
  3423.         // System.out.println(Thread.currentThread().getName()
  3424.         //     + " : " + name + " : Entering get...");
  3425.         // /* synchronized */(redrawAgainCount)
  3426.         {
  3427.             // System.out.println(Thread.currentThread().getName()
  3428.             //     + " : " + name + " : Inside get...");
  3429.             return redrawAgain;
  3430.         }
  3431.     }
  3432.  
  3433.    /**
  3434.     * The body of the async redraw thread
  3435.     */
  3436.     // Thread redrawer = new Thread(this);
  3437.  
  3438.     public /* synchronized */ void myWait()
  3439.         throws java.lang.IllegalMonitorStateException
  3440.     {
  3441.         try
  3442.         {
  3443.             wait();
  3444.         }
  3445.         catch (java.lang.InterruptedException e)
  3446.         {
  3447.         }
  3448.     }
  3449.  
  3450.     public void run() {
  3451.         // Thread.currentThread().setName(this.redrawerName);
  3452.         while(true) {
  3453.             try {
  3454.                 if (!getRedrawAgain())
  3455.                 {
  3456.                     try
  3457.                     {
  3458.                         myWait();
  3459.                     }
  3460.                     catch (java.lang.IllegalMonitorStateException e)
  3461.                     {
  3462.                         System.out.println(e.getMessage());
  3463.                         Thread.currentThread().yield();
  3464.                     }
  3465.                 }
  3466.                 else
  3467.                 {
  3468.                     Thread.currentThread().yield();
  3469.                 }
  3470.             } catch(Exception ex) {}
  3471.             // System.out.println(this.redrawerName
  3472.             //     + " recieved notification.");
  3473.             setRedrawAgain(false);
  3474.             redraw(true);
  3475.         }
  3476.     }
  3477.  
  3478.     protected /* synchronized */ void myNotifyAll()
  3479.         throws java.lang.IllegalMonitorStateException
  3480.     {
  3481.         // notifyAll();
  3482.         redraw(true);
  3483.     }
  3484.  
  3485.     /**
  3486.      * Request for an asynchronous redraw of the Grid.  Calling this function can
  3487.      * greatly increase the efficiency of scrolling and rapid cell movement.
  3488.      */
  3489.     protected void redrawAsync() {
  3490.         try {
  3491.             setRedrawAgain(true);
  3492.             try
  3493.             {
  3494.                 myNotifyAll();
  3495.             }
  3496.             catch (java.lang.IllegalMonitorStateException e)
  3497.             {
  3498.                 System.out.println(e.getMessage());
  3499.             }
  3500.         } catch(Exception ex) {
  3501.             ex.printStackTrace();
  3502.         }
  3503.     }
  3504.  
  3505.     /**
  3506.      * Inherited from Component
  3507.      */
  3508.     public /* synchronized */ boolean handleEvent(Event e) {
  3509.         if (isToolbarComponent(e.target)) {
  3510.             if (e.target == gotoButton) {
  3511.                 e.arg = gotoTextField.getText();
  3512.             }
  3513.             return eventHandler.handleToolbarEvent(e);
  3514.         }
  3515.  
  3516.         if (e.target == vsb && e.arg != null)    {
  3517.             switch(e.id) {
  3518.                 case Event.SCROLL_LINE_DOWN:
  3519.                     scrollLineDown();  break;
  3520.                 case Event.SCROLL_PAGE_DOWN:
  3521.                     scrollPageDown(); break;
  3522.                 case Event.SCROLL_PAGE_UP:
  3523.                     scrollPageUp(); break;
  3524.                 case Event.SCROLL_LINE_UP:
  3525.                     scrollLineUp(); break;
  3526.                 case Event.SCROLL_ABSOLUTE:
  3527.                     scrollUpDownAbsolute(vsb.getValue()); break;
  3528.             }
  3529.         }
  3530.  
  3531.         if (e.target == hsb && e.arg != null)    {
  3532.             if (leftCol != hsb.getValue()) {
  3533.                 hsbPosition = leftCol =  hsb.getValue();
  3534.                 redrawAsync();
  3535.             }
  3536.         }
  3537.  
  3538.         if (e.target instanceof Scrollbar) {
  3539.             requestFocus();
  3540.         }
  3541.  
  3542.         return super.handleEvent(e);
  3543.     }
  3544.  
  3545.     /**
  3546.      * Scrolls to the specified row.
  3547.      */
  3548.     public void gotoRow(int row) {
  3549.         this.requestFocus();
  3550.         if (row < topRow || row > topRow + getPageSize().height - 1) {
  3551.             scrollUpDownAbsolute(row);
  3552.         }
  3553.  
  3554.         setCurrentCell(row,1);
  3555.     }
  3556.  
  3557.     /**
  3558.      * Scrolls up to the specified row.
  3559.      */
  3560.     public /* synchronized */ void scrollUpTo(int newTop) {
  3561.         newTop = Math.max(0, newTop);
  3562.  
  3563.         if (newTop != topRow) {
  3564.             topRow = newTop;
  3565.             vsbPosition = topRow;
  3566.             vsb.setValue(vsbPosition);
  3567.             redrawAsync();
  3568.         }
  3569.     }
  3570.  
  3571.     /**
  3572.      * Scrolls in the direction required to make the specified row visible.
  3573.      */
  3574.     public void scrollUpDownAbsolute(int row) {
  3575.         if (row < topRow) {
  3576.             scrollUpTo(row);
  3577.         } else {
  3578.             scrollDownTo(row);
  3579.         }
  3580.     }
  3581.  
  3582.     /**
  3583.      * Scrolls the Grid one line up
  3584.      */
  3585.     public void scrollLineUp() {
  3586.         scrollUpTo(topRow - 1);
  3587.     }
  3588.  
  3589.     /**
  3590.      * Scrolls one page up
  3591.      */
  3592.     public void scrollPageUp() {
  3593.         scrollUpTo(topRow - getPageSize().height + 1);
  3594.     }
  3595.  
  3596.     /**
  3597.      * Scrolls down so the specified row will be visible.
  3598.      */
  3599.     public /* synchronized */ void scrollDownTo(int nextTop) {
  3600.            int lastRow = cells.rows()-1;
  3601.  
  3602.         try {
  3603.             lastRow = Math.max(lastRow,
  3604.                        dataSource.validDataRowRange(0, nextTop));
  3605.         } catch(DataNotAvailable ex) {}
  3606.  
  3607.         nextTop = Math.min(nextTop, lastRow);
  3608.  
  3609.         if (nextTop >= topRow) {
  3610.             vsbPosition = topRow = nextTop;
  3611.             vsb.setValue(vsbPosition);
  3612.             redrawAsync();
  3613.         }
  3614.     }
  3615.  
  3616.     /**
  3617.      * Scrolls down one line.
  3618.      */
  3619.     public void scrollLineDown() {
  3620.         scrollDownTo(topRow + 1);
  3621.     }
  3622.  
  3623.     /**
  3624.      * Scrolls down one page.
  3625.      */
  3626.     public void scrollPageDown() {
  3627.         scrollDownTo(topRow + getPageSize().height - 1);
  3628.     }
  3629.  
  3630.  
  3631.     /**
  3632.      * Gets whether a particular cell is currently being drawn.
  3633.      */
  3634.     public boolean isCellVisible(int row, int col) {
  3635.         row--;
  3636.         col--;
  3637.  
  3638.         boolean changed = false;
  3639.         int rc = cells.rows();
  3640.  
  3641.         try {
  3642.             rc = Math.max(rc, dataSource.validDataRowRange(0, row+1)+1);
  3643.         } catch(DataNotAvailable ex) {}
  3644.  
  3645.         row = Math.min(rc-1, row);
  3646.         row = Math.max(0, row);
  3647.         col = Math.min(col, splitters.length);
  3648.         col = Math.max(0, col);
  3649.  
  3650.         if (row < topRow
  3651.            || row > topRow + getPageSize().height
  3652.            || col+1 < leftCol
  3653.            || col+1 > leftCol + getPageSize().width)
  3654.         {
  3655.             return false;
  3656.         }
  3657.  
  3658.         return true;
  3659.     }
  3660.  
  3661.     /**
  3662.      * Makes the specified cell visible by scrolling as required.
  3663.      */
  3664.     public /* synchronized */ void makeCellVisible(int row, int col) {
  3665.         row--;
  3666.         col--;
  3667.         boolean changed = false;
  3668.         int rc = cells.rows();
  3669.  
  3670.         try {
  3671.             rc = Math.max(rc, dataSource.validDataRowRange(0, row+1)+1);
  3672.         } catch(DataNotAvailable ex) {}
  3673.  
  3674.         row = Math.min(rc-1, row);
  3675.         row = Math.max(0, row);
  3676.         col = Math.min(col, splitters.length);
  3677.         col = Math.max(0, col);
  3678.  
  3679.         // scroll UPWARD
  3680.         if (row < topRow) {
  3681.             topRow = row;
  3682.             vsbPosition = topRow;
  3683.             vsb.setValue(vsbPosition);
  3684.             changed = true;
  3685.         }
  3686.  
  3687.         // scroll DOWNWARD
  3688.         if (row > topRow + getPageSize().height - 1) {
  3689.             topRow = row - getPageSize().height + 1;
  3690.             vsbPosition = topRow;
  3691.             vsb.setValue(vsbPosition);
  3692.             changed = true;
  3693.         }
  3694.  
  3695.         // scroll LEFT
  3696.         col++;
  3697.         boolean scrollLeft = false;
  3698.         if (col < leftCol) {
  3699.             leftCol = (col<1)  ?1  :col;
  3700.             hsbPosition = leftCol;
  3701.             hsb.setValue(hsbPosition);
  3702.             scrollLeft = true;
  3703.             changed = true;
  3704.         }
  3705.  
  3706.         // scroll RIGHT
  3707.         Dimension pgSize = getPageSize();
  3708.         if (col != leftCol && col > leftCol + pgSize.width - 1) {
  3709.             hsbPosition = col;
  3710.             if (pgSize.width > 0) {
  3711.                 leftCol = hsbPosition -= (pgSize.width-1);
  3712.             }
  3713.  
  3714.             leftCol = hsbPosition;
  3715.             hsb.setValue(hsbPosition);
  3716.             changed = true;
  3717.         }
  3718.  
  3719.         if (changed) {
  3720.             if (scrollLeft) {
  3721.                 redraw(true);
  3722.             } else {
  3723.                 redrawAsync();
  3724.             }
  3725.         }
  3726.     }
  3727.  
  3728.     boolean postEvent(int id, int num) {
  3729.             Event e = new Event(this, id, new Integer(num));
  3730.             return postEvent(e);
  3731.     }
  3732.  
  3733.     Dimension getPageSize() {
  3734.         Dimension d = size();
  3735.         int i = leftCol;
  3736.  
  3737.         if (vsb.isVisible()) { d.width -= vsb.size().width; }
  3738.         for (;i<splitters.length;i++) {
  3739.             if (splitters[i] - splitters[leftCol-1] > d.width) {
  3740.                 break;
  3741.             }
  3742.         }
  3743.  
  3744.         d.width = i - leftCol;
  3745.  
  3746.         d.height -= bottomPanel.size().height;
  3747.         d.height = (d.height - headingHeight)/cellHeight;
  3748.  
  3749.         return d;
  3750.     }
  3751.  
  3752.     void drawHeadings(int numRowsToDraw) {
  3753.         //iterate headings and draw them
  3754.         int                 r = 0;
  3755.         MatrixEnumeration   e = colHeadings.elements();
  3756.         TableCell           c = null;
  3757.         int                 x, w;
  3758.         int                 cols = getNumberOfCols();
  3759.  
  3760.         //iterate the headings and paint each one
  3761.         while(e.hasMoreElements() || c != null) {
  3762.             //iterate the cols of the current row
  3763.             for (int col=leftCol-1; col<cols; col++) {
  3764.                 w = getColumnWidth(col);
  3765.                 while ((c == null || e.currCol() < col) && e.hasMoreElements()) {
  3766.                     c = (TableCell)e.nextElement();
  3767.                     if (e.currCol() < col) {
  3768.                         //keep going till get to correct column
  3769.                         c = null;
  3770.                     }
  3771.                 }
  3772.  
  3773.                 if (e.currCol() == col) {
  3774.                     hints.setHints(c);
  3775.                     c.drawCell(gg, hints);
  3776.                     c = null;
  3777.                 }
  3778.  
  3779.                 if (c != null) {
  3780.                     c = null;
  3781.                 }
  3782.             }
  3783.         }
  3784.  
  3785.         drawRowHeadings(numRowsToDraw);
  3786.     }
  3787.  
  3788.     /* synchronized */ void redrawColHeadingCell(int col) {
  3789.         if (col < leftCol-1 || col >= getNumberOfCols()) {
  3790.             //col heading not visible so get out now
  3791.             return;
  3792.         }
  3793.  
  3794.         TableCell cell = (TableCell)colHeadings.elementAt(0, col);
  3795.         hints.setHints(cell);
  3796.         cell.drawCell(gg, hints);
  3797.  
  3798.     }
  3799.  
  3800.     /* synchronized */ void redrawRowHeadingCell(int row) {
  3801.         if (!rowHeadingHints.visible || !validRow(row)) {
  3802.             //not drawing row heading so get out quickly
  3803.             return;
  3804.         }
  3805.  
  3806.         //if current cell is heading cell we need to draw it in proper state
  3807.         if (rowHeadingCell(currCaptureCell) && currCaptureCell.row() == row) {
  3808.             hints.setHints(currHeadingCell);
  3809.             currHeadingCell.drawCell(gg, hints);
  3810.         } else {
  3811.             TableCell       cell = headingCell.cloneCell();
  3812.  
  3813.             cell.setRow(row);
  3814.             hints.setHints(cell);
  3815.  
  3816.             cell.drawCell(gg, hints);
  3817.         }
  3818.     }
  3819.  
  3820.     void drawRowHeadings(int count) {
  3821.         if (!rowHeadingHints.visible) {
  3822.             //not drawing row heading so get out quickly
  3823.             return;
  3824.         }
  3825.  
  3826.         TableCell        cell = headingCell.cloneCell();
  3827.         Coordinate       c = cell.getCoordinates();
  3828.  
  3829.         for (int i=0; i<count; i++) {
  3830.             cell.setRow(i + topRow);
  3831.             hints.setHints(cell);
  3832.  
  3833.             cell.drawCell(gg, hints);
  3834.         }
  3835.  
  3836.         //if current cell is heading cell we need to draw it in proper state
  3837.         if (rowHeadingCell(currCaptureCell)) {
  3838.             hints.setHints(currHeadingCell);
  3839.             currHeadingCell.drawCell(gg, hints);
  3840.         }
  3841.  
  3842.         redrawCornerCell();
  3843.     }
  3844.  
  3845.     /* synchronized */ void redrawCornerCell() {
  3846.         //draw corner cell
  3847.         hints.setHints(cornerCell);
  3848.         cornerCell.drawCell(gg, hints);
  3849.     }
  3850.  
  3851.     Frame frame() {
  3852.         Container c = this;
  3853.         while(!(c instanceof Frame)) {
  3854.             c = c.getParent();
  3855.         }
  3856.  
  3857.         return (Frame)c;
  3858.     }
  3859.  
  3860. //-----------------------------------------------------------------------------
  3861. //          CellHints methods
  3862. //-----------------------------------------------------------------------------
  3863.  
  3864.     /**
  3865.      * Adds a CellHint dedicated to a row.
  3866.      * <p>This fucntion is 0 relative
  3867.      */
  3868.     public void addRowHint(int row, CellHints c) {
  3869.         row++;
  3870.  
  3871.         cellAttributes.addElement(row, 0, c);
  3872.     }
  3873.  
  3874.     /**
  3875.      * Adds a CellHint dedicated to a cell.
  3876.      * <p>This fucntion is 0 relative
  3877.      */
  3878.     public void addCellHint(int row, int col, CellHints c) {
  3879.         row++;
  3880.         col++;
  3881.  
  3882.         cellAttributes.addElement(row, col, c);
  3883.     }
  3884.  
  3885.     /**
  3886.      * Gets a CellHint dedicated to a cell.
  3887.      * <p>This fucntion is 0 relative
  3888.      */
  3889.     public CellHints getCellHints(int row, int col) {
  3890.         row++;
  3891.         col++;
  3892.  
  3893.         if (cellAttributes.contains(row, col)) {
  3894.             return (CellHints)cellAttributes.elementAt(row, col);
  3895.         } else {
  3896.             return null;
  3897.         }
  3898.     }
  3899.  
  3900.     /**
  3901.      * Gets a CellHint dedicated to a row.
  3902.      * <p>This fucntion is 0 relative
  3903.      */
  3904.     public CellHints getRowHints(int row) {
  3905.         row++;
  3906.  
  3907.         if (cellAttributes.contains(row, 0)) {
  3908.             return (CellHints)cellAttributes.elementAt(row, 0);
  3909.         } else {
  3910.             return null;
  3911.         }
  3912.     }
  3913.  
  3914.     /**
  3915.      * Gets a CellHint dedicated to a column.
  3916.      * <p>This fucntion is 0 relative
  3917.      */
  3918.     public CellHints getColHints(int col) {
  3919.         //column attributes must be set
  3920.         col++;
  3921.  
  3922.         return (CellHints)cellAttributes.elementAt(0, col);
  3923.     }
  3924.  
  3925.     /**
  3926.      * Gets the CellHints for a column heading<p>
  3927.      * row is zero relative<br>
  3928.      * col is one relative - with cornercell coord being 0
  3929.      */
  3930.     public CellHints getHeadingHints(int row, int col) {
  3931.         return (CellHints)headingAttributes.elementAt(row, col);
  3932.     }
  3933.  
  3934.     /**
  3935.      * Gets the cell alignment for the specified cell
  3936.      */
  3937.     public int getCellAlignment(TableCell c) {
  3938.         CellHints hc = getCellHints(c.row(), c.col());
  3939.         CellHints hr = getRowHints(c.row());
  3940.         CellHints h = getColHints(c.col());
  3941.  
  3942.         return h.cascadeAlignment(hr, hc);
  3943.     }
  3944.  
  3945.     /**
  3946.      * Gets the cell foreground for the specified cell
  3947.      */
  3948.     public Color getCellFG(TableCell c) {
  3949.         CellHints hc = getCellHints(c.row(), c.col());
  3950.         CellHints hr = getRowHints(c.row());
  3951.         CellHints h = getColHints(c.col());
  3952.  
  3953.         return h.cascadeForeground(hr, hc);
  3954.     }
  3955.  
  3956.     /**
  3957.      * Gets the cell background for the specified cell
  3958.      */
  3959.     public Color getCellBG(TableCell c) {
  3960.         CellHints hc = getCellHints(c.row(), c.col());
  3961.         CellHints hr = getRowHints(c.row());
  3962.         CellHints h = getColHints(c.col());
  3963.  
  3964.         return h.cascadeBackground(hr, hc);
  3965.     }
  3966.  
  3967.     /**
  3968.      * Gets whether a specified cell is editable according to the CellHints
  3969.      */
  3970.     public boolean getCellEditable(TableCell c) {
  3971.         CellHints hc = getCellHints(c.row(), c.col());
  3972.         CellHints hr = getRowHints(c.row());
  3973.         CellHints h = getColHints(c.col());
  3974.  
  3975.         return h.cascadeEditable(hr, hc);
  3976.     }
  3977.  
  3978.     /**
  3979.      * Determines whether the specified cell is highlighted
  3980.      */
  3981.     public boolean getCellHighlighted(TableCell c) {
  3982.         //adjust for all highlight functions being 1 relative
  3983.         int row = c.row() + 1;
  3984.         int col = c.col() + 1;
  3985.  
  3986.         if (c.type() == TableCell.COL_HEADING) {
  3987.             isColumnSelected(col);
  3988.         } else if (c == cornerCell) {
  3989.             return isViewSelected();
  3990.         } else if (rowHeadingCell(c)) {
  3991.             return isRowSelected(row) || isCellSelected(row, col);
  3992.         }
  3993.  
  3994.         //must be an honest to goodness cell
  3995.         return isCellSelected(row, col);
  3996.     }
  3997.  
  3998.     /**
  3999.      * Gets the font for the specified cell
  4000.      */
  4001.     public Font getCellFont(TableCell c) {
  4002.         CellHints hc = getCellHints(c.row(), c.col());
  4003.         CellHints hr = getRowHints(c.row());
  4004.         CellHints h = getColHints(c.col());
  4005.  
  4006.         return h.cascadeFont(hr, hc);
  4007.     }
  4008.  
  4009.     /**
  4010.      * Gets whether the specified cell should be drawn.
  4011.      */
  4012.     public boolean getCellVisibility(TableCell c) {
  4013.         if (rowHeadingCell(c)) {
  4014.             return rowHeadingHints.visible;
  4015.         }
  4016.  
  4017.         if (c.type() == TableCell.COL_HEADING) {
  4018.             return getHeadingHints(c.row(), c.col()+1).isVisible();
  4019.         }
  4020.  
  4021.         //get hints for cell, row, col and combine
  4022.         CellHints h = getCellHints(c.row(), c.col());
  4023.         if (h != null && !h.isVisible()) { return false; }
  4024.  
  4025.         h = getRowHints(c.row());
  4026.         if (h != null && !h.isVisible()) { return false; }
  4027.  
  4028.         //column has to be set
  4029.         h = getColHints(c.col());
  4030.         return h.isVisible();
  4031.     }
  4032.  
  4033. //-----------------------------------------------------------------------------
  4034. //          Selection control variables and member functions
  4035. //-----------------------------------------------------------------------------
  4036.  
  4037. //ALL OF THESE FUNCTIONS ARE ONE RELATIVE!!!!!!!
  4038.  
  4039.     /**
  4040.      * The bit set that defines which cells/rows/cols are selected. <BR>
  4041.      * bit 0 = corner cell <BR>
  4042.      * bit 1 - # of cols = columns <BR>
  4043.      * bit (# of cols) * row + 1 = rows <BR>
  4044.      * all other bits represent individual cells
  4045.      */
  4046.     BitSet      selected = new BitSet();
  4047.     Coordinate  selectionBase = null;
  4048.     Coordinate  selectionLimit = null;;
  4049.     boolean     selectionMade = false;
  4050.  
  4051.     /**
  4052.      * Gets whether the specified row is selected
  4053.      */
  4054.     public boolean isRowSelected(int row) {
  4055.         return selected.get(tx4Sxn(row));
  4056.     }
  4057.  
  4058.     /**
  4059.      * Gets whether the specified cell is selected
  4060.      */
  4061.     public boolean isCellSelected(int row, int col) {
  4062.         return selected.get(tx4Sxn(row, col));
  4063.     }
  4064.  
  4065.     /**
  4066.      * Gets whether the specified column is selected
  4067.      */
  4068.     public boolean isColumnSelected(int col) {
  4069.         return selected.get(col);
  4070.     }
  4071.  
  4072.     /**
  4073.      * Gets whether the whole grid is selected
  4074.      */
  4075.     public boolean isViewSelected() { return selected.get(0); }
  4076.  
  4077.     public void toggleCell(int row, int col) {
  4078.         if (!isRowSelected(row)) {
  4079.             toggleBit(tx4Sxn(row, col));
  4080.         }
  4081.     }
  4082.  
  4083.     /**
  4084.      * Gets a list of the coordinates for all of the selected cells
  4085.      */
  4086.     public Coordinate[] getSelectedCells() {
  4087.         Vector cells = new Vector();
  4088.         int cols = getNumberOfCols();
  4089.         int rows = sxnRows(cols);
  4090.  
  4091.         for (int row=1;row<rows;row++) {
  4092.             for (int col=1; col<cols; col++) {
  4093.                 if (selected.get(tx4Sxn(row, col))) {
  4094.                     cells.addElement(new Coordinate(row, col));
  4095.                 }
  4096.             }
  4097.         }
  4098.  
  4099.         Coordinate sxn[] = new Coordinate[cells.size()];
  4100.         cells.copyInto(sxn);
  4101.  
  4102.         return sxn;
  4103.     }
  4104.  
  4105.     /**
  4106.      * Gets the row number of the first selected row
  4107.      * @return The first selected row, -1 if none are selected
  4108.      */
  4109.     public int getFirstSelectedRow() {
  4110.         int cols = getNumberOfCols();
  4111.         int total = selected.size();
  4112.         int row = 1;
  4113.  
  4114.         for (int index=cols+1; index<total; index+=(cols+1), row++) {
  4115.             if (selected.get(index)) {
  4116.                 return row;
  4117.             }
  4118.         }
  4119.  
  4120.         return -1;
  4121.     }
  4122.  
  4123.     /**
  4124.      * Gets an array of all of the selected rows
  4125.      */
  4126.     public int[] getSelectedRows() {
  4127.         int cols = getNumberOfCols();
  4128.         int total = selected.size();
  4129.         int srows[] = new int[dataSource.rows()];
  4130.         int row = 1;
  4131.         int next = 0;
  4132.  
  4133.         for (int index=cols+1; index<total; index+=(cols+1), row++) {
  4134.             if (selected.get(index)) {
  4135.                 srows[next++] = row;
  4136.             }
  4137.         }
  4138.  
  4139.         int sxn[] = new int[next];
  4140.         System.arraycopy(srows, 0, sxn, 0, next);
  4141.  
  4142.         return sxn;
  4143.     }
  4144.  
  4145.     /**
  4146.      * Gets an array of all of the selected columns
  4147.      */
  4148.     public int[] getSelectedCols() {
  4149.         int cols = getNumberOfCols();
  4150.         int scols[] = new int[cols];
  4151.         int next = 0;
  4152.  
  4153.         for (int col=1; col<=cols; col++) {
  4154.             if (selected.get(col)) {
  4155.                 scols[next-1] = col;
  4156.                 next++;
  4157.             }
  4158.         }
  4159.  
  4160.         int sxn[] = new int[next];
  4161.         System.arraycopy(scols, 0, sxn, 0, next);
  4162.  
  4163.         return sxn;
  4164.     }
  4165.  
  4166.     /**
  4167.      * Determines whether the specified row is hightlighted
  4168.      */
  4169.     public boolean isRowSet(int row) {
  4170.         return selected.get(tx4Sxn(row));
  4171.     }
  4172.  
  4173.     /**
  4174.      * Selects the specified row
  4175.      */
  4176.     public /* synchronized */ void setRow(int row, boolean setTo) {
  4177.         int bit = tx4Sxn(row);
  4178.         int cols = getNumberOfCols();
  4179.  
  4180.         for (int i=0;i<=cols;i++) {
  4181.             if (setTo) {
  4182.                 selected.set(bit+i);
  4183.             } else {
  4184.                 selected.clear(bit+i);
  4185.             }
  4186.         }
  4187.  
  4188.         selectionMade = true;
  4189.         if (autoRedraw) { redrawRow(row); }
  4190.     }
  4191.  
  4192.     /**
  4193.      * Toggles the selection on the specified row.
  4194.      */
  4195.     public /* synchronized */ void toggleRow(int row) {
  4196.         int bit = tx4Sxn(row);
  4197.         boolean set = selected.get(bit);
  4198.         int cols = getNumberOfCols();
  4199.  
  4200.         for (int i=0;i<=cols;i++) {
  4201.             if (set) {
  4202.                 selected.clear(bit+i);
  4203.             } else {
  4204.                 selected.set(bit+i);
  4205.             }
  4206.         }
  4207.  
  4208.         selectionMade = true;
  4209.         if (autoRedraw) { redrawRow(row); }
  4210.     }
  4211.  
  4212.     /**
  4213.      * Toggles the selection for the specified column
  4214.      */
  4215.     public /* synchronized */ void toggleCol(int col) {
  4216.         boolean set = selected.get(col);
  4217.         int cols = getNumberOfCols();
  4218.         int total = selected.size();
  4219.  
  4220.         for (int i=col; i<=total; i+=(cols+1)) {
  4221.             if (set) {
  4222.                 selected.clear(i);
  4223.             } else {
  4224.                 selected.set(i);
  4225.             }
  4226.         }
  4227.  
  4228.         selectionMade = true;
  4229.         if (autoRedraw) { redrawAsync(); }
  4230.     }
  4231.  
  4232.     /**
  4233.      * Either clears all cell selections or selects all cells.
  4234.      */
  4235.     public /* synchronized */ void toggleAll() {
  4236.         if (selected.get(0)) {
  4237.             //clear all bits
  4238.             clearAllSelections();
  4239.         } else {
  4240.             //set all of them
  4241.             int total = selected.size();
  4242.             for (int i=0; i<total; i++) {
  4243.                 selected.set(i);
  4244.             }
  4245.             selectionMade = true;
  4246.         }
  4247.  
  4248.         if (autoRedraw) { redrawAsync(); }
  4249.     }
  4250.  
  4251.     /**
  4252.      * Unselects all cells.
  4253.      */
  4254.     public /* synchronized */ void clearAllSelections() {
  4255.         if (selectionMade) {
  4256.             selectionBase = null;
  4257.             selectionLimit = null;
  4258.             selectionMade = false;
  4259.             selected.xor(selected);
  4260.             if (autoRedraw) { redrawAsync(); }
  4261.         }
  4262.     }
  4263.  
  4264.     /**
  4265.      * Sets the cell by which range selections are performed
  4266.      */
  4267.     public void setSelectionBase(int row, int col) {
  4268.         selectionBase = new Coordinate(row, col);
  4269.     }
  4270.  
  4271.     /**
  4272.      * Determines whether a selection base cell has been set.
  4273.      */
  4274.     public boolean isSelectionBaseSet() {
  4275.         return selectionBase != null;
  4276.     }
  4277.  
  4278.     /**
  4279.      * Determines if a range of cells are currently selected.
  4280.      */
  4281.     public boolean isRangeSelected() {
  4282.         return selectionLimit != null;
  4283.     }
  4284.  
  4285.     //need to provide for erasing values in cells then make public
  4286.     void eraseRangeSelection() {
  4287.         //need to turn autoRedraw off while doing this
  4288.         setRange(false);
  4289.     }
  4290.  
  4291.     /* synchronized */ void setRange(boolean setTo) {
  4292.         //if value == true then set bits o.w. clear bits
  4293.         if (selectionBase == null) { return; }
  4294.  
  4295.         if (selectionLimit == null) {
  4296.             selectionLimit = selectionBase;
  4297.         }
  4298.  
  4299.         int topRow = Math.min(selectionBase.row, selectionLimit.row);
  4300.         int topCol = Math.min(selectionBase.col, selectionLimit.col);
  4301.         int bottomRow =  Math.max(selectionBase.row, selectionLimit.row);
  4302.         int bottomCol =  Math.max(selectionBase.col, selectionLimit.col);
  4303.  
  4304.         //need to turn autoRedraw off while doing this
  4305.         boolean auto = autoRedraw;
  4306.         autoRedraw = false;
  4307.  
  4308.         //check for two rows defining range
  4309.         if (selectionBase.col == 0 && selectionLimit.col ==0) {
  4310.             //two row selections made - this is easy case
  4311.             for (int row=topRow; row<=bottomRow; row++) {
  4312.                 setRow(row, setTo);
  4313.             }
  4314.         }
  4315.  
  4316.         autoRedraw = auto;
  4317.         if (autoRedraw) { redrawAsync(); }
  4318.     }
  4319.  
  4320.     /**
  4321.      * Clears all selections
  4322.      */
  4323.     public void clearRangeSelection() {
  4324.         eraseRangeSelection();
  4325.         selectionBase = null;
  4326.         selectionLimit = null;
  4327.     }
  4328.  
  4329.     /**
  4330.      * Selects the range that spans from the currently selected base cell to
  4331.      * the specified row and column.
  4332.      */
  4333.     public /* synchronized */ void selectRange(int limitRow, int limitCol) {
  4334.         //if no base, then we do not select any rows
  4335.         if (selectionBase == null) {
  4336.             selectionBase = new Coordinate(limitRow, limitCol);
  4337.         }
  4338.  
  4339.         boolean auto = autoRedraw;
  4340.         autoRedraw = false;
  4341.  
  4342.         //erase old range and draw new one
  4343.         eraseRangeSelection();
  4344.  
  4345.         selectionLimit = new Coordinate(limitRow, limitCol);
  4346.         setRange(true);
  4347.  
  4348.         autoRedraw = auto;
  4349.         if (autoRedraw) { redrawAsync(); }
  4350.     }
  4351.  
  4352.     /**
  4353.      * Selects a range of cells and sets the base for future selections
  4354.      */
  4355.     public void selectRange(int baseRow, int baseCol, int limitRow, int limitCol) {
  4356.         //if previous selection erase
  4357.         clearRangeSelection();
  4358.  
  4359.         //create a new range base
  4360.         selectionBase = new Coordinate(baseRow, baseCol);
  4361.         selectRange(limitRow, limitCol);
  4362.  
  4363.     }
  4364.  
  4365.     final void toggleBit(int bit) {
  4366.         selectionMade = true;
  4367.         if (selected.get(bit)) {
  4368.             selected.clear(bit);
  4369.         } else {
  4370.             selected.set(bit);
  4371.         }
  4372.     }
  4373.  
  4374.     //1 relative
  4375.     final int tx4Sxn(int row, int col) {
  4376.         return tx4Sxn(row) + col;
  4377.     }
  4378.  
  4379.     //1 relative
  4380.     final int tx4Sxn(int row) {
  4381.         int cols = getNumberOfCols();
  4382.  
  4383.         return (cols+1) * (row);
  4384.     }
  4385.  
  4386.     final int sxnRows(int cols) {
  4387.         return (int)Math.ceil(selected.size() / (cols + 1f));
  4388.     }
  4389. }
  4390.  
  4391.  
  4392.  
  4393.  
  4394.